Skip to content
This text was generated by an LLM (how cgwalters uses LLMs). cgwalters has not reviewed it yet.

Where the code lives

This is the contributor's map. Commands, configuration and exit states are in interface.md; deployment is in workflow.md.

Rust workspace

crates/agentic-job contains the library and the agentic-job binary. The same crate builds fake-agent, the scripted ACP agent used by tests. Releases publish both binaries for the reusable workflow's scripted runs.

crates/secure-host is the host's side, for any job that runs code it does not trust: it depends on nothing that runs an agent (no ACP, inference, safe outputs, sessions or run), which cargo tree -p secure-host shows, and agentic-job depends on it, never the reverse. The split is under way (#1623). So far it holds bounded file reads (files.rs), host users and the programs root may run (host.rs), the network rules (network.rs), the egress proxy's setup and the proxy itself (egress.rs, proxy/) with the [egress] table (config.rs), the mount view (view.rs), the probe of reachable listeners (local.rs), the platform, apt and world-write steps (platform.rs, apt.rs, world_write.rs) and the Worker-diagnostics rule (worker_diagnostics.rs); agentic-job re-exports each at its old path (files, sandbox::host, config::Egress, secure_host::apt, ...). Two seams keep agents out: agentic-job's main hands host::bare the agent's variables to leave out too, and gives egress::start the binary and command that run the proxy. The sandbox user, helper, probes, the image and the secure-host binary still live in agentic-job's sandbox/ and secure_host/ below.

Paths below are relative to crates/agentic-job/src/.

PathResponsibility
main.rs, cli.rs, exit.rsCommand dispatch and exit states
config/TOML types, validation and composition from workflow inputs
policy.rsBounds, per-run policy and gh-aw configuration
event/Event admission, run guards and fenced task context
check/Output policy and strict mail-patch parsing
collect/gh-aw's collector and sanitizer, ported: handback check, check.yml and callers off GitHub
apply/Publishing checked outputs behind Publisher; Forgejo only
audit.rsOffline artifact inspection and finding codes
workflows/Workflow job-shape rules and bounded YAML reading
redact.rsSecret redaction
sandbox/setup.rs, sandbox/setup/Host preparation: the lock, the sandbox user, the agents and tools
sandbox/check/Host, runner-lock and network probes
sandbox/enter.rsEntry as the sandbox user
sandbox/helper.rs, sandbox/root.rsFixed privileged operations and their callers
session/ACP transport, permissions, limits, transcript and digest
run/Clone, inference registration, agent configuration, session orchestration and hand-back
acp_drive/acp-drive: the daemon and commands that drive a run's child agent

The supervisor runs as the runner's user. With --runner-home, the reusable workflow's default (agent-user: runner), run uses no sandbox user and the agent shares the supervisor's uid; without it (agent-user: sandbox), its file operations in the sandbox run as the sandbox user, through run/enter.rs (requirements.md). After setup, privileged operations go through the root-owned helper; tests on hosts without setup can use sudo directly. The helper's validation is a security boundary, not a generic root command runner.

The session

session::run(Options) drives one task. It receives an agent registry entry, launch wrapper, permission policy, limits, request-count channel and output paths. It records acp.jsonl, agent-stderr.log and harness.json. run owns cleanup on signals as well as normal completion.

session/agents.toml is the built-in registry. The session's digest is also used to summarize recorded transcripts. session/clients.rs has a notification tap, but no client can attach to a running task yet.

run

run/clone.rs clones the public target as the sandbox user before run/inference.rs registers the run. run/agent.rs writes agent settings; run/launch.rs clears inherited provider settings and starts the agent. run/probe.rs checks where the run token is, not the whole host sandbox.

run/brief.rs tells the agent how to hand back, and handback.rs lets it check what it would hand back during the session. run/handback.rs reads the outcome and requests and makes one patch from the uncommitted tree. run/log.rs, run/egress.rs and run/summary.rs build redacted evidence; run/upload.rs gates publication. Failed cleanup or remaining secrets leave nothing to upload. The interface and artifact guide describe the outputs.

Adding an agent

An ACP command in the registry is not enough for run. A new agent needs configuration and launcher code that pins its provider and keeps project settings from redirecting the run token. It also needs a known token file, environment filtering, API route, instruction-file handling and cost interpretation. See run/agent.rs, run/launch.rs, session/process.rs and their table tests.

Task limits depend on recognizing the agent's subagent tool names. Spending limits depend on reported ACP usage; request limits depend on the inference proxy. Test these against the actual adapter, not only generated configuration. The agent-extension recipe lists the files to change, the adapter contract and the security tests.

Other directories

secure-host/ holds the standalone action, hosted configuration, release pin and binary-fetch script. egress/ holds the mitmproxy addon, policy, hashed dependencies and Python tests; the Rust proxy, the default in place of mitmproxy, is crates/secure-host/src/proxy/. The runtime Python files, default policy, ecosystem identifiers and requirements file are embedded in the binary; the tests are not. Regenerate the identifiers with python3 egress/ecosystems.py GH_AW_CHECKOUT when changing gh-aw's pin. skills/ holds the agents' skills and subagents, also embedded.

safe-outputs/ holds integration scripts, derived validation rules and fixtures. gh-aw's handlers come from its pinned setup action, not a vendored copy; collect is held to its collector at the same commit. Regenerate the rules with node safe-outputs/validation.mjs GH_AW_CHECKOUT when changing that pin, and collect's parity fixtures with just collect-fixtures GH_AW_JS.

Tests and CI

Unit tests sit beside Rust code. Binary integration tests are in crates/agentic-job/tests/. Its corpus/ directory compares policy and patch behavior with the old tree at the pin recorded in plan.md, and runs collect and check against gh-aw's pinned handlers with a mocked forge. Those Node tests require separate old-tree and gh-aw checkouts; their source files document the environment variables.

ci.yml runs Rust formatting, clippy and tests, Markdown linting and offline links, proxy tests and release-pin checks (one lint job), static builds, sandbox mutation tests and scripted-agent E2E runs. The ci job gathers their results. Host tests need disposable runners with root and systemd 257; they are not safe to run on a workstation.