Repository navigation
Releases: olafkfreund/AIFactory
Release list
v3.10.12
Five behaviour changes: acw_ API keys authenticate for the first time
(with expiry, owner status, a live role cap and org binding), viewers can
no longer mint write-scoped keys, a JWT role=admin no longer bypasses org
checks, GET /api/admin/access-review takes only ?org_id, and
GET /api/audit/export needs org admin. Remote MCP now authorizes each call
as the calling key; it stays off by default (AIFACTORY_MCP_REMOTE_ENABLED).
A task needing plan review now always pauses after its planner, and
auto-fix routes need project roles. One new env var:
AIFACTORY_AGENT_COMMIT_TRAILERS (default off). The model
gateway ships as a separate -gateway image that nothing deploys. No
migrations.
Changed
acw_keys authenticate (#1914, closes #1913). Before, every real key
failed (REST 401, stdio and remote MCP 500). The lookup now refuses a key
whose owner is missing or deactivated, a key pastexpires_at, a key whose
org is deleted, and a key with no effective scopes. Effective scopes follow
the owner's current role inkey.org_id(below member:mcp:readonly; no
membership: none). REST needs the explicitapiscope. Key principals are
bound tokey.org_idfor project access, list filters, project create,
org-role routes and git-credential routes. Mint withexpires_in_daysnow
works on Postgres.- Viewers cannot mint write-scoped keys (#1911, closes #1908).
POST /api/keysgives a caller belowmembera 403 for any scope other
thanmcp:read. Existing keys are not revoked (#1914 caps them live). is_service_principaltrusts onlyis_service(#1911, closes #1909).
A JWT withrole=adminno longer bypasses org checks. Auth-disabled dev
principals are markedis_service, so dev mode is unchanged.GET /api/admin/access-reviewstreams only the gated org (#1916, closes
#1915). It takes only?org_id;?orgis gone. Before,
?org_id=A&org=Blet an admin of A read B's roster.GET /api/audit/exportrequires org admin (#1916). Non-service callers
must passorg_idand holdadminin it (read from the DB). Anacw_key
can export only its own org. Service principals are unchanged.- Remote MCP authorizes each tool call as the calling key (#1917, closes
#1910). Read tools need viewer and write tools need member on the
project the call proxies to;list_projectsis filtered to the key's org;
ids are validated against path escapes; an SSE session accepts messages
only from the key that opened it. Remote MCP stays off unless
AIFACTORY_MCP_REMOTE_ENABLEDis set; it is not set in factory-gitops. - Plan-review gate decided from pre-planner state (#1926, closes #1922).
A task that needs plan review always pauses after its planner session; a
planner clearing the flag or forgingreview_state.jsonhas no effect.
An approval withoutspec_hashno longer counts. Start passes--force
only on a hash-valid approval or the server'stask_control.planApproved
record (set by approve-plan, cleared by reject-plan and any plan-review
pause); otherwise the task is held in plan review. - Auto-fix routes need project roles; reused specs are not forced past
review (#1928, closes #1925). GET queue needsviewer; GET config,
check-new and{N}/startneedmember; PUT config needsadmin. GET
config returns the bot token masked (********); PUT keeps the stored
token on the mask or a missing field, and""clears it. Starting an
issue whose spec already exists no longer forces past plan review.
requireHumanApprovalnow setsrequireReviewBeforeCodingon created
specs. - Worktree spec sync mirrors only allowlisted build files (#1923, closes
#1921). On the subprocess backend an agent could overwrite canonical
task_metadata.json,review_state.json,COMPLETED.jsonand others
from its worktree. Onlytoken_usage.json,guardrail_halt.jsonand
handback_received.jsonare mirrored now. Kubejob builds never ran this
sync.
Added
- Agent commit trailers, off by default (#1907, Factory#1960 slice 3).
AIFACTORY_AGENT_COMMIT_TRAILERSaddsAgent-Identity,Autonomy-Tier
andOriginatortrailers to AIFactory's parallel-wave and safety-net
commits. Off leaves the commit argv unchanged. With the flag on, the
localmerge --no-ff, the Approve squash and the PR-endgame auto-merge
carry them too, and the squash body becomes only the trailer block
(#1918). - Model gateway image (#1912, Factory#1959 stage 0a).
ghcr.io/olafkfreund/aifactory:{sha-*,latest,v*}-gateway, built and
Trivy-scanned on PRs, cosign-signed by digest on deploy and release, and
SBOM-attested on release. Its own env vars (GATEWAY_UPSTREAM_URL,
GATEWAY_UPSTREAM_API_KEY,GATEWAY_CLIENT_TOKEN,GATEWAY_PORT) apply
to the gateway container only. Nothing deploys it.
Deprecated
- The LiteLLM sub-chart (#1912). Chart comments and a docs admonition
only; removal is a later slice.
v3.10.11
Four behaviour changes: APP_DEBUG no longer relaxes the disable-auth or
wildcard-CORS boot guards (each has its own opt-in), and
POST /api/tasks/from-issue now checks project membership and binds a
declared repo to the project's own repo.
Four new env vars: APP_ALLOW_INSECURE_AUTH, APP_ALLOW_WILDCARD_CORS
(both default false), AIFACTORY_ROUTE_RESOLUTION (default off) and
AIFACTORY_MODEL_CATALOG_PATH (default unset). No migrations.
Changed
APP_DISABLE_AUTHoff loopback needsAPP_ALLOW_INSECURE_AUTH(#1895,
Factory#312).APP_DEBUG=truealone no longer lets the server boot with
auth disabled on a non-loopback host. Same name as PFactory and TFactory.
Never set in production.- A wildcard CORS origin needs
APP_ALLOW_WILDCARD_CORS(#1902,
Factory#312).APP_DEBUG=truealone no longer lets the server boot with
*inAPP_CORS_ORIGINS. With the opt-in it still warns and turns off
credentialed CORS. An explicit allowlist is unchanged. POST /api/tasks/from-issuerequiresmemberon the target project
(#1899, closes #1898). A foreignacw_key gets 403. The legacy service
token (intake poller) is unaffected.- A
repodeclared toPOST /api/tasks/from-issuemust be the project's
own repo (#1901, closes #1900). Host, path and provider are compared
against the project'sgitRepo,clonedFromand checkoutorigin;
anything else, or a declaration on a project with no known repo, gets 400.
A request withoutrepois unchanged.
Added
- Catalog route resolution, off by default (#1896, Factory#1959 slice 5).
AIFACTORY_ROUTE_RESOLUTION(off/shadow/on) resolves a contract
route tier to a model from the RFC-0014 catalog at
AIFACTORY_MODEL_CATALOG_PATH, replacing only the built-inDEFAULT_TIERS
fallback. Runshadowfirst: the catalog must mark superseded models
available: false. - Task originator recorded at intake (#1897, Factory#1960 slice 2).
originatorandagent_identityare stored in the spec's
requirements.jsonfor MCP, REST/CLI, project and GitHub-import intake
(from-issue only when fetched through the project's provider), and returned
byGET /api/tasks/{id}. Unknown stays null. No migration.
Fixed
- Comma-separated
APP_CORS_ORIGINSno longer crashes boot; anull
origin is treated like*(#1904, closes #1903). An empty
APP_CORS_ORIGINS=now means no origins; unset keeps the localhost
defaults.
CI and tests
v3.10.10
Two behaviour changes: the stdio-MCP task proxies now enforce project access,
and an acw_ key can no longer mint keys.
One alembic migration (7a1f3c9e2b50, adds api_keys.autonomy_ceiling).
Changed
- MCP task proxies enforce project access (#1885, closes #1882; #1891).
/api/mcp-stdio/...routes now check theacw_key owner's project role as
the REST routes do, after the scope check. Write routes (create-and-run,
start, stop, recover, approve-plan, apply-correction, create-pr, merge) need
member; read routes (task details, status, logs, diff) needviewerand
return 403/404 for a foreign project./projects,/tasksand
/tasks/runningare filtered to the key owner's orgs. The legacy service
token and anacw_key with no user stay service principals and are
unaffected. - An
acw_key can no longer mint keys (#1887).POST /api/keyswith an
acw_key gets a 403; mint keys with a user session.
Added
- Autonomy ceiling and agent identity on
acw_keys (#1887,
Factory#1960 slice 1). New nullableApiKey.autonomy_ceiling
(low/medium/hard, no default) via alembic7a1f3c9e2b50, and a derived
agent_identity(agent:aifactory/<key_id>). The key create and list routes
accept and return them. Only an org admin can set a ceiling (403
otherwise). Not wired into the merge path yet, so no merge
decision changes. - MCP
task_apply_correctionpassestriagethrough (#1881, closes #1874).
Adds the missingPOST /api/mcp-stdio/tasks/{task_id}/apply-correction
proxy route (gated bytask:write), so the MCP tool works again under the
3.10.9 triage default. A 422 without triage now explains both fixes. - TFactory ingest forwards the pre-overlay signed contract (#1883,
TFactory#1432). Sent as top-levelsigned_contractfor signed, non-held
contracts;contractis unchanged. Warn mode only on the TFactory side.
Fixed
- Completion webhook sends
APP_API_TOKENto CFactory (#1888,
CFactory#501). Completion and outbox POSTs to/api/eventscarry
Authorization: Bearer $APP_API_TOKEN, only when the target matches the
configured webhook origin. No token, no header. CFactory is in warn mode. GET /api/tasks?project_id=<unknown>returns 404, not 500 (#1890, closes
#1889). Also fixes the MCPtask_listproxy.- SBOM attestation fits rekor's size limit (#1884, closes #1879). Each
image's SPDX SBOM is attested without file entries (packages kept), after
the 3.10.9 -nix attestation exceeded rekor's 24 MiB request limit.
CI and tests
- P0 acceptance image build is cached in a gha layer cache (#1880, closes
#1875). - Test pins the provider credentials that reach dispatched Jobs (#1886,
Factory#1959).
Chores
- Baked agent-CLI pins: claude-code 2.1.310, gemini-cli 0.65.0, codex 0.164.0
(#1871).
v3.10.9
Two behaviour changes: the runtime image moves to CPython 3.15, and
apply-correction now requires a triage block by default.
Changed
- Runtime image moves to CPython 3.15 (#1873, closes #1842). The image is
built on the currentcgr.dev/chainguard/python:latest-devdigest
(CPython 3.15.0). A newpy-buildstage compiles the venv; lxml, xmlsec and
real-ladybug build from sdist with--require-hasheskept, andruntime
adds the systemxmlsec/libxml2-16/libxsltlibraries. The lock is
recompiled for 3.15 (pydantic 2.14, asyncpg 0.32, grpcio 1.84.1, uvloop 0.23
and others). The CI P0 docker job now allows a 1800 s image build in a
50-minute job. - Apply-correction requires a triage block by default (#1872,
TFactory#1431).APP_REQUIRE_CORRECTION_TRIAGEnow defaults to on: a
POST /api/tasks/{id}/apply-correctionwith notriageblock, including a
markdown-only call, gets a 422 before anything is written. TFactory 0.9.42
sends triage on every handback path (TFactory#1436). Opt out with
APP_REQUIRE_CORRECTION_TRIAGE=false. Known gap: the MCP
task_apply_correctiontool has no triage input yet, so it also gets the 422
until #1874 lands.
Security
v3.10.8
Security
- Outbound PII scrub is mandatory for regulated projects (#1862,
Factory#320). A new project settingdataClassification
(public|internal|confidential|regulated) is stored as
AIFACTORY_DATA_CLASSIFICATION. Projects classifiedregulatednow always
get outbound PII scrubbing: theLITELLM_AUDIT_SCRUB_OUTBOUND=false
kill-switch and per-adapter_scrub_outboundpins are ignored for them, and
an unreadable settings store fails closed toregulated. The default
classification staysinternal, and the other tiers are unchanged. A bad
value is a 422. Directclaude --printspawns are a known gap, tracked in
#1860.
Added
- Verify verdict and vote split as PR evidence (#1863, Factory#1963).
Auto-merge PRs get a "Verify evidence" section in the body with the verify
verdict, TFactory's vote split and the floor signals (host CI, VAL against
the floor, CI parity). The verdict is evidence; the deterministic floor still
decides, and a write failure never changes the gate result. - Optional
APP_REQUIRE_CORRECTION_TRIAGEgate (#1861, closes #1858). When
on,POST /api/tasks/{id}/apply-correctionrejects a request with no
triageblock with a 422 before anything is written. Default off until
TFactory skills post a triage block (TFactory#1430). - Memory duplicate-rate baseline (#1856, RFC-0021, #389).
scripts/memory_dup_baseline.pyand the first measured baseline in
docs/dev/memory-baseline-2026-10.md.
Chores
v3.10.7
Fixed
- Four real CodeQL hygiene alerts (#1853, Factory#813). The
_refresh_to_remote_baselog lines now pass branch, path and git stderr
throughsanitize_log(log injection), a no-opterminal_status
self-assignment is gone, and_WrappedResponseStream._captureinitialises
msg_typebefore itstry, with a regression test.
Tests
- A pass verdict cannot merge past a red floor (#1854, Factory#1963). An
end-to-end test throughrun_pr_endgameand the realwatch_and_finish
proves that red host CI, VAL below the floor, orci_parityfalse never
callsmerge_pr.
Chores
- follow-redirects 1.16.0 -> 1.16.1 in
/docs(#1845).
v3.10.6
Security
- npm-bundled undici 6.29.1 and brotli floors (#1851). The npm
vendored-deps overlay moves undici 6.28.1 -> 6.29.1 (CVE-2026-109869) and apk
floors pulllibbrotlicommon1/libbrotlidec1/libbrotlienc1to 1.2.0-r7
(CVE-2026-111497), clearing the new HIGH CVEs the Trivy P0 gate reported. - dompurify 3.4.17 (#1851). The override floor moves to
^3.4.17, past
GHSA-cg2g-xh64-v4q7 (critical) and GHSA-mrv2-3pqr-j5jr, which failed the
Trivy P0 gate on the frontend lockfile.
v3.10.5
Security
- Runtime image floors (#1841). apk floors pull
curland
libcurl-openssl4to 8.23.0-r0 andca-certificates-bundleto
20260909-r3, and certifi moves to 2026.10.19, clearing the new HIGH CVEs the
Trivy P0 gate reported. apk delno longer pretends to removepy3-pip-wheel(#1844,
TFactory#1350). python-3.14 depends on it, so apk refused and exited 0. It
now ships deliberately, and the build asserts the pip packages that are
removed really are gone.
Fixed
- An unmeasured value is not a definite answer (#1557). The merge baseline
and the bwrap probe no longer treat a missing measurement as a pass or a
fail.
Documentation
- Kubejob is the supported isolated host for trusted plans (#1846, closes
#1760 and #1724).host_isolated()stays kubejob + durable store only; the
PID-namespaced sandbox is not widened, because a same-uid agent could read the
per-call GitHub token.
Chores
v3.10.4
Security
- aiohttp 3.14.3 -> 3.14.5 (#1836). Fixes CVE-2026-111064 (no initial
request/header timeout) and GHSA-2g87-pp6c-29x5 (unbounded memory and CPU
on crafted requests). yarl moves 1.24.5 -> 1.25.1 with it. The Trivy gate
on PRs to dev failed until this landed. - Server-side git no longer runs repo filters, and a late baseline is
visible (#1832, PR #1837).merge_driver_pinsnow also pins
filter.<x>.clean,.smudgeand.processempty for every configured
filter, and every server-sidegit status,git add, worktree-reading
git diffand the unforcedgit worktree removeuse the pins. A
requiredfilter is left unpinned, so git exits 128 and the call fails
closed; if the pins cannot be read the call refuses and a status probe
reports "has changes". The git metadata baseline is now recorded before
the spec pipeline's agents and before a build's first agent session, which
covers direct mode and builds without workspaces. A baseline taken late
still passes, but the build output now printsWARNING: git metadata baseline taken late for <repo>; changes made before now are not detected. - Git metadata baseline follow-ups (#1832). The baseline now also
trackslfs.customtransfer.*.path,lfs.*standalonetransferagentand
submodule.*.updateset to!cmd, so a change to any of them fails the
check. Withextensions.worktreeConfig, each worktree's
config.worktreeis compared with its own baseline, so one worktree's
config no longer reads as drift in another, and a change to it is still
reported. A project slug of.git-baselinesis refused, and
resolve_pr_conflictsremoves a baseline file it created for a build
clone. A repo whose old baseline holds per-worktree keys reports drift
once; rebaseline withpython -m core.git_metadata --rebaseline <path>.
Changed
- Baked agent-CLI pins (#1411):
@anthropic-ai/claude-code2.1.303,
@openai/codex0.163.0,@google/gemini-cli0.64.0. PFactory and
TFactory pin the same versions. - Dependency bumps: GitHub Actions group (#1744: setup-uv 10.3.0,
kind-action 1.15.1, setup-node 7.1.0, sbom-action 0.24.3, codeql-action
4.39.0, upload-artifact 7.0.2, download-artifact 8.0.2); npm
source-map-js 1.2.2 (#1739); and in/docssource-map-js 1.2.2 (#1654),
shell-quote 1.12.0 (#1653), proxy-addr 2.0.8 (#1655) and compression
1.8.2 (#1656).
v3.10.3
Added
- Opt-in repo lint gate (#1742). With
AIFACTORY_REPO_LINT_GATE=1, the
trailing gates run the target repo's CI linters that AIFactory has a
curated command for (ruff check .,flake8,ktlint), never the CI
step text. A lint that fails goes toGATE_FAILURES.mdand the QA fix
loop; a missing tool readsskipped. The planner prompt also names the
linters CI runs. Off by default, because it can fail builds that pass
today.ci_lintersnow refuses a repo with more than 64 workflow files.
Security
- Legacy and from-issue tasks need a real verified green to auto-merge (#1697).
Tasks without a signed contract (including MODE 0 from-issue tasks) now
go through the same merge-time gate as signed ones: auto-merge needs a
TFactory pass and green host CI on the head commit. A missing verdict or
missing CI now counts as not passed, andtask_metadata.jsoncan only
tighten these signals, never loosen them. The path risk floor is always
enforced for these tasks, whateverAIFACTORY_PATH_RISK_FLOOR_ENFORCE
says. Breaking for projects without TFactory or without CI: their
legacy and from-issue tasks no longer auto-merge. The PR stays open and
the watcher times out to a human stop. - Agent children can no longer read the parent's secrets through
/procor$HOME(#1762).
Each agent CLI spawn (Claude SDK paths, codex, copilot, gemini/antigravity,
opencode and the tool-loop Bash) gets a private 0700 HOME that holds only
that CLI's login file and a.gitconfigwithuser.*andsafe.directory.
A refreshed login is written back only if the real file is unchanged. If
the private HOME cannot be built the spawn fails; nothing falls back to the
real HOME. Agent children also get an env allowlist (#1757), so
SSH_AUTH_SOCKand other inherited names are dropped. Breaking for
operators: agents lose~/.sshand home-folder tool configs; add needed
env names withAIFACTORY_AGENT_ENV_EXTRA, and name an MCP server's host
vars withenv_keys. On local runners the/procwindow stays open (#1724).