This records the locally installed integration surfaces checked for the MVP (Pi 1.1.0 and Herdr 0.9.3; Herdr API schema protocol 22). No live agent was started during this check.
Task runner and step planner
Each active task is driven by its own Rust task runner: the TUI starts cronos-ai --data-dir <dir> internal workflow run-task <project-id> <task-id> in its own process group. The runner loops over the task's agent steps and stops at a human approval, the local merge, Error, or Completed. Each progress line it prints on stdout is shown in the dashboard; a non-zero exit carries the end of its stderr as the error. Rust is the source of truth for project and task state and for every human control.
Before each agent step the runner asks a step planner for the agents. It is a one-shot Pi run in the task worktree, pi -p --mode text --no-session --no-approve with discovery off and only read-only tools (read,grep,find,ls), on the project's planner model when one is set (project set-planner-model). Its prompt carries the task and its OpenSpec change, the step's job and agent limits, the profiles allowed in the step, the current attempt's changes_requested findings (from reviewers, verifiers, the check command, and merges), the human's revision note, and any clarification. Its answer must contain {"agents": [{"name": ..., "prompt": ..., "profile_id": ...}]}; Rust validates it exactly like a run-step request. When the planner fails, takes more than five minutes, or proposes an invalid plan, the runner runs a default one-agent plan with a templated prompt carrying the same context and records the reason as orchestrator activity. Rust then appends its own contract to every prompt and starts the agents through Herdr. tests/live_smoke.rs checks the real step planner and one real Pi agent when CRONOS_LIVE_SMOKE=1 is set.
Herdr agent API
Herdr 0.9.3 exposes agent operations through its socket API and CLI. The installed API schema advertises agent.start, agent.prompt, agent.wait, agent.read, and agent.send_keys.
agent.startrequires a supported agent kind and an existing pane at an interactive shell prompt. For Pi, use kindpi; readiness is reported only after Herdr detects the expected agent in that pane.agent.promptsubmits work;agent.waitcan observeworking,idle,blocked, ordone;agent.readretrieves terminal output.- Interrupt an active agent with
agent.send_keysusingctrl+c, then observe the agent state. This is terminal-level cancellation and is best-effort; do not treat the key submission alone as proof that the agent stopped. Ignore late results after the workflow has entered Error. - Cancellation is sticky within a step: Cronos remembers which agents were cancelled and checks before splitting a pane, after starting the agent, and before reading its result, so a sibling that had not started yet never starts after its step failed.
- Each agent gets its own pane, which Cronos closes with
pane closewhen the agent finishes, fails, or is cancelled. Agents left by a crashed process are found withagent get(itspane_id), interrupted, and their panes closed on resume or recovery. - Herdr agent names are
c<task>-<step>-<agent>-<hash>, at most 32 characters. The hash is a stable FNV-1a hash of the task ID, attempt, and agent name, so names never collide across attempts and stay the same across Cronos builds. - Workflow-time agent operations run in a Herdr-managed pane with caller context (
HERDR_ENV=1). Direct TUI startup does not create panes. The explicitscripts/cronos-ailauncher is the opt-in exception: outside Herdr it creates a dedicated workspace and pane in the namedcronos-aisession, runs Cronos-AI there, and never replaces or targets unrelated panes; inside Herdr it uses the current pane. - The step planner sees the user-configured profile IDs allowed for the current step in its prompt and can assign one profile per agent. Rust validates those assignments before starting any agent, and Herdr forwards explicit skill/extension/MCP config arguments to each Pi worker without shell interpolation. Every worker starts with Pi discovery off, then loads the built-in skill for its step (written from the binary to
<data-dir>/skills/<name>/SKILL.md) and its profile's resources. See workflow-agent profiles for setup. - The project planner is a separate, one-shot Pi run (
pi -p --mode text --no-session --no-approve) in the project repository with discovery off, read-only tools (read,grep,find,ls), and only thecronos-project-planningskill. Its final answer must end with a fenced JSON plan; Rust validates it and never creates tasks until a human applies it. Its process group is stopped at the time limit.
CLI help and the installed API schema confirm these command/parameter contracts. The Rust adapter invokes Herdr with argument vectors (never a shell), validates agent names, parses pane IDs from Herdr responses, and waits for a settled state after sending ctrl+c. A workflow step creates no-focus sibling panes only after explicit task start, and only in the task's validated worktree under the Cronos data directory. Startup preflight checks pi, herdr, openspec, and git by running their version commands; if any are unavailable it prompts for manual installation and retries, but never installs tools. Only the explicit scripts/cronos-ai launcher creates its dedicated Herdr workspace, avoiding existing user panes. Automated launcher tests use fake Herdr commands; live pane/agent launch, prompt, output, and cancellation checks must run in an explicitly isolated test session, not the current user session.
Git worktrees and local merge
Projects store the canonical root of a user-selected local Git repository. When a task is started, Rust creates an isolated worktree under the Cronos data directory and a branch named cronos-ai/<task-id>/attempt-<n>. Recovery removes the exact validated prior-attempt worktree and branch before assigning a fresh attempt. Specification and code generation agents commit their own work. Final-code approval gates the documentation step, after which Rust archives the OpenSpec change and makes one documentation commit. When the task runner stops at local merge, Rust requires both the base repository and task worktree to be clean and performs a local git merge --no-ff --no-edit. If the merge leaves unmerged paths, Rust aborts it and returns the task to code generation to resolve the conflict; any other merge failure is aborted and marks the task Error. With the push publish mode, Rust then pushes the base branch to the project's remote with an explicit refspec; with pull-request, it pushes the task branch instead of merging and opens (or reuses) a pull request with gh pr create. Git and gh run with GIT_TERMINAL_PROMPT=0 and GH_PROMPT_DISABLED=1, so missing credentials fail the step instead of prompting. Agents themselves never push.
Check command
The project check command runs without a shell in the task worktree after the verification agents, in its own process group so reaching the project's check time limit (60 minutes unless the project sets 1 to 480) stops everything it started. Output goes to .cronos/check-output.log, which Cronos creates fresh and never writes through a symlink. A non-zero exit, or new files left in the worktree, sends the task back to code generation. A relative program such as ./scripts/check.sh runs the task branch's version; if the branch changed it, Cronos records a warning for the human reviewer.
Trust boundary
Agents and the planners have no way to change task status, approvals, or worktree paths through Cronos: agents only write their result files, and the planners only answer with plans that Rust validates. Rust validates every step, profile, and transition and checks the worktree after each step. Workers, however, are full Pi sessions with shell access running with your operating-system permissions: a worker's shell could edit Cronos data files, leave the worktree, change tests or the check program, or push. The human approval gates and the review view are the real protection.
With project set-sandbox on, each worker instead runs in a write sandbox (sandbox-exec on macOS, bubblewrap on Linux): it can still write its worktree, the repository's Git objects, build caches, and temporary files, but not Cronos data, the base checkout, or the repository's .git/hooks and .git/config. The sandbox does not limit network access or reading files, and a worker can still weaken tests inside its worktree, so the human gates remain the real protection. Run Cronos-AI as a dedicated OS user or in a container for untrusted work.
Prioritizer (Jev)
The original design picked Jev, a fast selection model, to choose the next task. Cronos-AI runs that decision as a one-shot Pi call instead, so it works with any model Pi can reach: pi -p --mode text --no-session --no-tools --no-approve with discovery off and --model from project set-prioritizer --model (Pi's default model otherwise). Set the model to Jev once Pi can run it.
The prompt lists only the tasks the scheduling rules already allow to start, under keys T1, T2, ..., plus the running tasks. The answer must contain {"order": ["T2", "T1"], "reason": "..."}; Rust rejects unknown or repeated keys, keeps omitted tasks after the ranked ones in built-in order, and falls back to the built-in order on any failure or after two minutes. The reason is recorded as prioritizer activity on the first task started.