A coding-agent harness that converts external signals into planned, built, tested, reviewed, secured, documented, and memory-backed software changes — and can open a draft pull request for the result. The harness owns lifecycle, governance, routing, memory, and the verifier (the sole pass/fail authority); an executor (Claude Code by default in real runs; mock for CI) does the actual coding work.
The design philosophy: evidence-first, governance-gated, model-independent. The coding agent never grades its own work, stubs fail loudly rather than silently, and every side-effectful action is opt-in and gated.
| Version | Capability |
|---|---|
| v1.1 | Real executor layer + capability verifier; Windows portability (cross_platform_run, python -m pytest) |
| v1.2 | Bounded retry loop — on real test failure, failure context is fed back to the executor and retried (--max-attempts) |
| v1.2.2 | Windows prompt path fixed — prompt piped via stdin (claude -p), never a shell-parsed positional |
| v1.3 | Robust executor JSON parse (model from modelUsage, actionable auth errors); diff hygiene (pyc/cache excluded); real review/security/docs agents that analyze the actual diff; opt-in draft PR creation |
| v1.4 | Scoped, auditable security waivers — a signal can authorize a specific finding without defeating the scanner |
bash scripts/dev.sh # install
bash scripts/test.sh # 68 tests
factory run --signal examples/sample-signal.json # mock executor, artifact grading# Requirements: ANTHROPIC_API_KEY in env, `claude` (Claude Code CLI) on PATH
# Install Claude Code: npm i -g @anthropic-ai/claude-code
# Initialize the demo target as a git repo on a non-protected branch
cd examples/demo-target && git init -b feature/factory && \
git add -A && git -c user.email=t@t -c user.name=t commit -m init
cd ../..
# Run
factory run \
--signal examples/demo-signal.json \
--target-repo examples/demo-target \
--executor claude_code \
--max-attempts 2 # v1.2: retry up to 2 attempts if tests failThe factory writes the run artifacts plus coding-diff.patch (the real diff) to .factory-runs/{run_id}/. The diff is left uncommitted in the target repo's working tree — you decide whether to commit/PR/discard.
# Requires GITHUB_TOKEN in env (fine-grained PAT: Contents + Pull requests
# write on the target repo). The target repo must have a GitHub origin.
factory run \
--signal examples/demo-signal.json \
--target-repo /path/to/repo-with-github-origin \
--executor claude_code \
--max-attempts 2 \
--create-pr --pr-base mainPR creation is gated on ALL of: opt-in (--create-pr), a real target repo, verifier decision == pass, and governance approval. The factory opens a draft PR and never merges. The token is read from env only — never logged, never written to artifacts.
| Executor | grading_mode | pass iff |
|---|---|---|
mock |
artifact |
artifacts present AND synthetic tests pass AND security pass |
claude_code |
capability |
artifacts present AND real tests_exit_code == 0 AND non-empty diff AND security pass |
The coding agent's self-assessment is always ignored. The verifier decides.
All three read the unified diff and scan added lines only (removing a problem doesn't trip the scanner; unchanged context isn't re-flagged). Deterministic, dependency-free, no LLM calls — they run on every factory run.
- Review (
overall in {pass, needs_changes}, non-blocking) — flags TODO/FIXME, debug prints, bareexcept:, broad handlers, breakpoints, stubbedpass, over-long lines, large diffs, and source-changed-without-tests. Governance-blocked steps remain high-severity. High severity →needs_changes. - Security (
overall in {pass, fail}, verifier-blocking) — detects API keys, private keys, hardcoded credentials, and dangerous calls (eval/exec/os.system/subprocess shell=True/pickle.loads/yaml.load/verify=False/#nosec). Any unwaived critical/high →fail. - Documentation (
overall == pass, advisory) — detects public API changes vs. whether docs were updated; emits adocumentation_gap+ concrete recommendations.
A signal can authorize a specific security finding without disabling the scanner:
"security_waivers": [
{
"pattern_id": "shell-true",
"file": "scripts/deploy.py",
"reason": "deploy step needs a shell pipeline",
"approved_by": "emory"
}
]Semantics (conservative by design):
- A waiver only downgrades a matched finding to
status: "waived"— never hides it. Waived findings are recorded inreport["waived"]with reason + approver. Transparency over silent suppression. - A waiver must name a specific
pattern_id. There is no blanket waive-all. reasonandapproved_byare required; a malformed waiver is ignored (finding stays active) and counted inmalformed_waivers.- Only unwaived critical/high issues block the run.
Stable pattern ids: anthropic-openai-key, aws-access-key, private-key-block, github-pat, slack-token, hardcoded-credential, eval, exec, shell-true, os-system, pickle-loads, yaml-load, tls-verify-false, nosec-comment.
signal -> triage -> planning
|
v
+---- executor router ----+
| mock | claude_code | (prompt via stdin; model-independent)
+-------------|-----------+
v
coding <--- bounded retry loop (v1.2)
| (failure context fed back on real test failure)
v
testing (real: python -m pytest)
|
v
review -> security -> documentation (v1.3: real analysis over coding-diff.patch)
| security waivers applied here (v1.4)
v
VERIFIER (capability | artifact) <- sole pass/fail authority
|
(if pass + --create-pr + governance) -> draft PR (v1.3)
|
v
memory (SQLite)
See docs/architecture.md, docs/executors.md.
src/
signals/ triage/ planning/ router/ workflows/
executors/{mock,claude_code}/ # claude_code pipes prompt via stdin
agents/{coding,testing,review,security,documentation}/ # review/security/docs real (v1.3)
integrations/github/ # draft PR creation (v1.3, stdlib urllib)
memory/ governance/ utils/ factory_cli/
docs/ examples/{demo-target/,*.json} scripts/ tests/
- Pre-flight on every real run: target_repo must exist, be a git repo, on a non-protected branch, clean (override with
--allow-dirty/--allow-protected-branch). - Action gates: destructive shell, hardcoded secrets,
production_deploy, autonomy > 2 — all blocked. - PR creation is a governed action — gated on verifier pass + autonomy level; draft-only, never merges.
- See
docs/governance.md.
| Flag | Default | Purpose |
|---|---|---|
--signal |
(required) | path to signal JSON |
--target-repo |
none | repo the executor operates on (real runs) |
--executor |
mock |
mock or claude_code |
--test-cmd |
none | e.g. "python -m pytest -q" |
--max-attempts |
2 | retry budget on real test failure (v1.2) |
--allow-dirty |
off | bypass clean-tree preflight |
--allow-protected-branch |
off | bypass protected-branch preflight |
--create-pr |
off | open a draft PR if verifier passes (v1.3; needs GITHUB_TOKEN) |
--pr-base |
main |
base branch for the PR |
docs/architecture.md— system shapedocs/executors.md— executor layerdocs/autonomy-levels.md— 0..3 with cap at 2docs/governance.md— blocked actions, target-repo preflightdocs/model-router.md— provider adaptersdocs/memory.md— SQLite schema + migrationsdocs/runbook.md— operating procedures, including extending
v1.4 — bounded retry loop; Windows stdin prompt path; real review/security/docs agents over the actual diff; opt-in draft PR creation; scoped auditable security waivers. Default autonomy=2, default max_attempts=2. Draft-only PRs; no production-deploy automation. 68 tests.
- Durable orchestration. Runs are single-process and synchronous; there is no step-level checkpoint or crash-resume. This is intentional for operator-supervised Diagnostic/Pilot use. It becomes a real liability at the first unattended, scheduled run (e.g. a Retainer's weekly cadence), where a crash could orphan a run or duplicate a PR. Adopt a durable orchestrator (e.g. Inngest/Temporal or a checkpointed queue) before the first scheduled cadence.
- Self-extension. The factory consumes signals a human places; it does not author its own pipeline stages or schedule itself. Intentional, given the deterministic/auditable design goals.