mecha_core/lib.rs
1//! `mecha-core` — a standalone agent harness.
2//!
3//! The library knows nothing about any particular CLI, UI, or project. It gives
4//! you four things and lets you wire them together:
5//!
6//! * [`provider`] — talk to a model (Anthropic, or anything OpenAI-shaped)
7//! * [`tool`] — things the agent can do, native or [`mcp`]-backed
8//! * [`agent`] — the loop that puts those together
9//! * [`session`] / [`batch`] — persistence and fan-out around the loop
10//!
11//! ```no_run
12//! # async fn example() -> anyhow::Result<()> {
13//! use mecha_core::{agent::Agent, agent::Conversation, config::Config};
14//! use mecha_core::sandbox::Sandbox;
15//! use mecha_core::tool::{ModeApprover, Registry, ToolCtx};
16//! use std::sync::Arc;
17//!
18//! let cfg = Config::load(&std::env::current_dir()?)?;
19//! let (_, provider_cfg) = cfg.provider(None)?;
20//!
21//! // How `shell` is confined. It decides that tool's declared capabilities,
22//! // so it is built before the registry rather than consulted at call time.
23//! let sandbox = Arc::new(Sandbox::new(cfg.sandbox.clone()));
24//!
25//! let agent = Agent::new(
26//! mecha_core::provider::build(provider_cfg)?,
27//! Registry::new().with_builtins(&cfg.tools, sandbox),
28//! Arc::new(ModeApprover { mode: cfg.tools.permission_mode }),
29//! ToolCtx {
30//! workspace: std::env::current_dir()?,
31//! shell_timeout: std::time::Duration::from_secs(cfg.tools.shell_timeout_secs),
32//! security: cfg.security.clone(),
33//! ..ToolCtx::default()
34//! },
35//! cfg.agent.clone(),
36//! None,
37//! )?;
38//!
39//! // A conversation carries its own taint, so keeping it across turns keeps
40//! // the trifecta interlock honest — see `agent::Conversation`.
41//! let mut convo = Conversation::user("What changed in this repo today?");
42//! let outcome = agent.run(&mut convo, None).await?;
43//! println!("{}", outcome.text);
44//! # Ok(())
45//! # }
46//! ```
47
48pub mod agent;
49pub mod batch;
50pub mod compact;
51pub mod config;
52pub mod counterfactual;
53pub mod cron;
54pub mod distill;
55pub mod eval;
56pub mod frontdoor;
57pub mod hooks;
58pub mod learning;
59pub mod mcp;
60pub mod message;
61pub mod outbox;
62pub mod provider;
63pub mod replay;
64pub mod replay_run;
65pub mod sandbox;
66pub mod search;
67pub mod session;
68pub mod subagent;
69pub mod tool;
70pub mod trigger;
71pub mod work;
72
73pub use agent::{Agent, AgentEvent, RunOutcome};
74pub use config::Config;
75pub use message::{Block, Effort, Message, Role, StopReason, Usage};
76
77pub const VERSION: &str = env!("CARGO_PKG_VERSION");
78
79/// Create a directory (and its parents) and make the leaf owner-only.
80///
81/// Transcripts, staged outbox drafts, the learning store and spilled tool
82/// output all carry the user's private data — mail bodies included, now that
83/// mail is wired — so their directories get the rule the mail token files
84/// already enforce on themselves (0600). The leaf only, on purpose: parents
85/// like `~/.mecha` also hold things the user may deliberately share, and the
86/// sensitive data lives below the leaf. Idempotent, and tightens a
87/// pre-existing directory too.
88pub fn create_private_dir(dir: &std::path::Path) -> std::io::Result<()> {
89 std::fs::create_dir_all(dir)?;
90 #[cfg(unix)]
91 {
92 use std::os::unix::fs::PermissionsExt;
93 std::fs::set_permissions(dir, std::fs::Permissions::from_mode(0o700))?;
94 }
95 Ok(())
96}