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/.
| Path | Responsibility |
|---|---|
main.rs, cli.rs, exit.rs | Command dispatch and exit states |
config/ | TOML types, validation and composition from workflow inputs |
policy.rs | Bounds, 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.rs | Offline artifact inspection and finding codes |
workflows/ | Workflow job-shape rules and bounded YAML reading |
redact.rs | Secret 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.rs | Entry as the sandbox user |
sandbox/helper.rs, sandbox/root.rs | Fixed 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.