Expand description
Render a loaded compose into on-disk artifacts.
Outputs under <root>/state/:
envs/<project>-<agent>.env— env vars for the agent wrapper.mcp/<project>-<agent>.json— MCP stdio config for the runtime.claude/<project>-<agent>.json— wrapper-managed Claude Code settings (currently aPreToolUsedeny hook for synchronous-prompt tools that strand a headless pane). Claude-code agents only.role_prompts/<project>-<agent>.md(multi-file role_prompt only) — the ordered concatenation of every source file declared in the role’srole_prompt: [...]list. Re-materialized on every render so any source-file edit lands in the agent’s prompt at next boot.
systemd / launchd unit rendering lives behind a feature flag when
those back-ends are enabled via supervisor.type.
Functions§
- agent_
scope_ dir - Absolute path to the per-agent scope directory passed to Claude Code
via
--add-dir(#383 Phase 3b). render materializes<this>/.claude/skills/<name>symlinks to each declared skill; the wrapper adds--add-dir <this>so the agent discovers them on top of the project.claude/skills/. The directory is materialized only when the agent declaresskills:; the wrapper’s[ -d ]guard decides whether the flag is passed. - boot_
script_ path - Absolute path to the shared boot-context hook script (#430). Wired into
every claude-code agent’s
SessionStarthook and rewritten byteamctl up(seeensure_wrapper_and_dirs), so it sits beside the agent wrapper inbin/rather than under per-agentstate/. One script serves all agents — it reads the wakesourcefrom stdin, so it needs no per-agent identity baked into the path. - claude_
settings_ path - Absolute path to the wrapper-managed Claude Code settings file. The
file carries the default
PreToolUsedeny hook for synchronous-prompt tools (AskUserQuestion,EnterPlanMode,ExitPlanMode) so a headless agent doesn’t strand on a picker no one will answer. The wrapper applies it viaclaude --settings <path>for every claude-code agent except those inpermission_mode: attended. - env_
path - Absolute path to the rendered env file for a given agent.
- heartbeat_
path - Absolute path to the per-agent activity heartbeat marker (#428). The
PreToolUse/UserPromptSubmithookstouchit on activity and theStop/StopFailurehooksrmit at turn-end; the TUIstats its mtime at the 1s refresh and classifies the agent Working (touched within 15s) or Idle. NOT JSON — a bare marker whose mtime is the whole signal. Compound<project>-<agent>like every sibling helper, so agents that share a name across projects never collide on one marker. - lastseen_
path - Per-agent “last seen” marker, a sibling of
heartbeat_path(#439). The boot-context hooktouches it at clean turn-end — alongsiderm-ing the heartbeat marker — so a freshly woken session can compute how long the agent was down. Unlike the heartbeat marker (removed at every turn-end, so present at boot only after an unclean shutdown), this one persists across the gap, making its mtime the agent’s last activity. Same compound<project>-<agent>stem as every sibling so cross-project name clashes can’t collide, with a.lastseensuffix so it never shadows the marker the TUI stats for Working/Idle. - mcp_
path - Absolute path to the rendered MCP config for a given agent.
- render_
agent - Rendered env + MCP content for a single agent.
- render_
claude_ settings - Wrapper-managed Claude Code settings JSON for a single agent. Returns
Some(json)forclaude-coderuntime regardless ofpermission_mode— the wrapper decides whether to apply it. ReturnsNonefor runtimes that don’t read Claude settings (codex, gemini, …). - render_
subagents - #383 Phase 3a: build Claude Code’s
--agentsinline JSON for one agent from its declaredsubagents:list. Each list entry is a compose-root-relative markdown file with standard sub-agent frontmatter (name,description, optionaltools,model) and a body that becomes the sub-agent’s systemprompt. The result is the{ "<name>": { description, prompt, [tools], [model] } }object the--agentsflag consumes — the only cwd-stationary way to scope sub-agents per agent (no arbitrary-path flag exists; see the Phase-1 spike). ReturnsOk(None)when none are declared (→ no--agentsflag) or the runtime isn’t claude-code (logs an “unsupported” warning, claude-only v1);Errif a source is unreadable or its frontmatter is invalid, so a typo fails the apply loudly rather than dropping a sub-agent silently. - role_
prompt_ concat_ path - Absolute path to the materialized concatenation of a multi-file
role_promptlist. Only ever written for the list form — single-filerole_promptkeeps pointing at its source path directly. - subagents_
json_ path - Absolute path to the rendered Claude Code
--agentsJSON for one agent (#383 Phase 3a). Lives beside the settings file understate/claude/and is written only when the agent declaressubagents:; the wrapper passes it via--agents "$(cat <path>)"when the file exists. - system_
prompt_ path - Resolve the absolute path that
SYSTEM_PROMPT_PATHwill point at. - write_
agent_ skills - Materialize (or clear) the per-agent skills scope for one agent (#383
Phase 3b). For a claude-code agent declaring
skills:, this createsstate/agent-scope/<project>-<agent>/.claude/skills/and symlinks each declared skill directory into it (link name = the skill dir’s basename), soclaude --add-dir <scope>surfaces them additively atop the project.claude/skills/. Mirrorswrite_subagents_json: the scoped + full render paths both call it, and the skills dir is rebuilt from scratch every render so a renamed or dropped skill never lingers. When the agent declares no skills (or isn’t claude-code) the scope dir is removed if present. - write_
role_ prompt_ concat - Materialize the multi-file
role_promptconcatenation for one agent. - write_
subagents_ json - Write (or clear) the per-agent
--agentsJSON file. Mirrorswrite_role_prompt_concat: the scoped + full render paths both call it so asubagents:edit flows into the agent at the next render. When the agent declares no sub-agents (or isn’t claude-code) the file is removed if present, so a stale--agentsset never lingers across a reload that dropped them.