Core vs Platform#
Carpenter separates platform-agnostic logic from platform-specific implementations:
- Core (
carpenter-ai) — Arc management, review pipeline, trust system, agent loop, model selection, skills, memory - Platform packages (
carpenter-linux,carpenter-android, etc.) — Executors, sandbox backends, network egress enforcement, platform-specific tools
Platform packages are thin. They register their implementations at startup, then hand off to the core:
from carpenter import (
set_platform, register_executor,
set_sandbox_provider, add_tool_dir
)
set_platform(LinuxPlatform())
register_executor("subprocess", SubprocessExecutor())
set_sandbox_provider(LinuxSandboxProvider())
add_tool_dir("/path/to/platform/tools")This means the core never imports platform-specific code. New platforms (Android, Windows, macOS) are independent packages that plug into the same core.
Executor Backends#
Code execution is handled by pluggable executor backends:
| Type | Isolation level |
|---|---|
| Subprocess (basic) | Same-user, env isolation, close_fds, RLIMIT_AS |
| Subprocess (standard) | Different-UID, RLIMIT_AS, optional Landlock |
| Docker (single) | Platform + executor in one container |
| Docker (orchestrator) | Separate containers |
The platform detects available sandbox methods and falls back gracefully. All subprocess executors enforce a configurable virtual memory limit (default 300MB) via RLIMIT_AS.
Tool System#
Tools are partitioned by safety:
carpenter_tools/
read/ — safe, direct agentic access
act/ — requires reviewed codeThe @tool() decorator declares safety properties: local, readonly, side_effects, trusted_output. A validation function enforces that read/ tools are all safe and act/ tools have at least one unsafe property.
The trusted_output=False declaration (currently only on the web tool) feeds into the taint tracking system — output from untrusted tools is never returned directly to the chat agent.
Model Selection#
A YAML models manifest declares available models with metadata:
provider— Anthropic, Ollamamodel_id— full model identifiercost_tier— low / medium / highcontext_window— token limitroles— which task types the model suits
Arc creation accepts a short name (e.g., "opus") that resolves to the full provider:model_id. Templates can specify model_min_tier per step — security review steps require high tier, preventing cost optimization from undermining review quality.
Presets#
Four built-in presets route requests to appropriate models:
| Preset | Use case |
|---|---|
fast-chat | Quick conversational responses |
careful-coding | Thorough code generation and review |
background-batch | Cost-optimized batch processing |
caretaker | System monitoring and maintenance |
Resilience#
Both AI clients use exponential backoff with jitter for transient failures and a per-provider circuit breaker that fast-fails after consecutive errors. The circuit breaker transitions through CLOSED → OPEN → HALF_OPEN states. HTTP 429 responses are handled by the rate limiter (natural cooldown via sliding window) rather than the circuit breaker.
Configuration#
All settings via config.yaml or environment variables. Three-layer precedence:
env vars > credential files > YAML > built-in defaultsNo hardcoded credentials in the package. The platform process holds all secrets and exposes them to executors only through the callback RPC layer.