All notable changes to CodeFRAME are documented here.
The format is based on Keep a Changelog, and this project aims to follow Semantic Versioning.
0.9.1 could not work for anyone and should not be used: it pinned five Anthropic model IDs that have since been retired, so every LLM-backed command returned a 404 on a fresh install even with a valid API key (#1112). The IDs were already corrected in the repository and had simply never been released.
Over 200 further commits since v0.9.1. SECURITY.md supports only the latest release, so the
security section below is the one to read before deploying anything older.
Several of these change defaults and will require configuration on an existing deploy.
WORKSPACE_ROOThas one meaning and fails closed (#896). It is anos.pathsep-separated allowlist of permitted workspace roots, never a location, and nothing creates it. The server now refuses to start when auth is enforced and no allowlist is set — an empty allowlist let any authenticated user open a session, and therefore a terminal shell, in any host directory.CODEFRAME_ALLOW_UNRESTRICTED_WORKSPACES=1is the documented single-operator local escape hatch.- Bootstrap registration is gated (#897).
POST /auth/registeris unauthenticated by design for the first account. It now requiresCODEFRAME_BOOTSTRAP_TOKENas anX-Bootstrap-Tokenheader, or a genuinely host-local request. Required for any deploy reachable over a network: without it, a fresh instance is claimable as admin by whoever reaches the route first. - Scopes are real, not decorative (#898). A JWT principal's scopes derive from its
user row —
read/writealways,adminonly for a superuser — sorequire_scope(SCOPE_ADMIN)now genuinely refuses a non-superuser browser session on credential storage and PR merge. Only a superuser may mint an admin-scoped API key. Workspace-registry ownership is write-once, so one user can no longer take over another's registeredrepo_path. - Untrusted-repository boundaries closed. A cloned repo can commit files that used to
steer the process: lifecycle hooks now require a recorded trust decision (#905), a
repo-supplied
llm.base_urlis refused unless it is loopback or explicitly opted into (#903), every.envvariant is ignored rather than an enumeration (#895), and a repository.envcan no longer override the operator's environment or supply security-steering keys (#904). - Subprocess containment. Plan-engine and gate subprocesses run with one allowlisted
environment (#907), plan-engine file operations are confined to the workspace (#906),
review_files()likewise (#899), and secrets are stripped from the LLMrun_commandenvironment (#721). Delegated coding CLIs run with a sandboxed$HOMEby default (#996) — 69 inherited environment variables including 5 API keys, down to 12 and none. - Streams no longer carry JWTs in URLs (#745). An authenticated
POST /auth/stream-ticketmints a 60-second single-use ticket, accepted as?ticket=on the two SSE and two WebSocket routes only.?token=<JWT>is no longer accepted anywhere. - Outbound webhook SSRF is blocked at dispatch, not only at save (#746, #656).
send_eventresolves the host, rejects private/loopback/link-local/metadata/CGNAT addresses, and pins the vetted IPs into the connector — defeating a hand-edited config and DNS rebinding (e.g.169.254.169.254). - Credential handling (#772).
CODEFRAME_CREDENTIAL_SECRETmixes into the PBKDF2 KDF for the encrypted-file fallback; unset, the key derives from the non-secret machine id alone, which is obfuscation and not confidentiality. Credentials are per-user scoped in hosted mode (#790), and sharing them across trust domains is blocked (#718). - Hosted multi-tenancy. Session REST endpoints are owner-scoped with TOCTOU path
revalidation (#704), GitHub PR endpoints are scoped to the caller's credential and repo
(#900),
GET /workspaces/existsenforces the allowlist (#719), and registry list/delete are owner-scoped (#720). - Auth hardening. The server hard-fails on a default
AUTH_SECRETwhenever auth is enabled (#643);/auth/jwt/loginand/auth/registerare rate-limited (#644); the JWT lifetime dropped from 7 days to 24 hours and the web UI ships a CSP (#657); the security-event taxonomy is actually emitted rather than merely defined (#937); a disabled account cannot log in (#938); and the test-only/test/broadcastroute is behindCODEFRAME_ENABLE_TEST_ENDPOINTS(#753). - The server warns at startup when in-memory rate limiting is used with multiple workers, where each worker keeps its own counters and the effective limit multiplies (#678).
-
A release guard that fails the build on an unresolvable model default (#1112).
scripts/check_model_defaults.pyruns beforeuv buildand rejects any dated model ID in the defaults or at a live call site, and — withMODEL_GUARD_REQUIRE_LIVE=1, as the release job sets — verifies each default actually resolves against the API. A missingANTHROPIC_API_KEYsecret fails the release rather than silently skipping the check. -
Phase 5.5 — GitHub Issues import. Connect a repo with a PAT from Settings → Integrations (#563), browse its open issues with search, label filter and pagination (#564), and import selected issues as tasks with
github_issue_number/external_urltraceability, atomic dedupe, and opt-in auto-close when the task reaches DONE (#565). -
Phase 5.4 — PRD stress-test in the web UI. An SSE endpoint streams goal analysis live (#561); results render as severity-tagged ambiguity cards, and answering the blocking ones folds them into a new PRD version (#562).
-
Phase 5.3 — Async notifications. A browser + in-app notification centre with workspace-scoped persistence (#559), a cross-page watcher so batch completions and new blockers fire even when the execution page is unmounted (#652), and an outbound webhook with a test button (#560).
-
Phase 5.2 — Cost visibility. Spend summary (#557) plus per-task and per-agent breakdowns, with an inline cost badge on task cards (#558).
-
Phase 5.1 — Settings. Working Agent, API Keys and PROOF9-defaults tabs (#554–#556);
run_proof()honoursenabled_gatesandstrictness. -
Server-side PROOF9 merge gate (#731).
POST /api/v2/pr/{n}/mergeblocks while open (non-waived) requirements exist. An explicitoverride: true+override_reasonbypasses it and records an audit entry (actor, reason, bypassed requirements, timestamp), surfaced asmerge_overrideinGET /api/v2/pr/history. A proof-ledger failure blocks the merge with an explicit 500 rather than silently allowing it.cf pr mergeenforces the same gate with--override --reason "...". -
Worktree isolation with real merge-back (#787), so parallel agents no longer share a tree.
-
Per-user credential scoping for hosted mode (#790).
-
A rewritten Playwright browser suite for the Phase-3+ UI (#684), with the config starting both servers itself.
-
A proactive web-UI auth guard plus an SSE/WebSocket token-expiry re-auth path (#651).
-
Retired Anthropic model IDs in the published package (#1112). The
DEFAULT_*_MODELconstants use undated aliases (claude-sonnet-4-5,claude-haiku-4-5), which Anthropic repoints, rather than dated IDs, which it retires. -
cf authreported valid API keys as invalid (#1112). Key validation probedclaude-3-haiku-20240307, itself already retired. It now uses the shared alias, as does the settings API's Anthropic key verification. -
Token/cost data was silently dropped:
react_agentint-cast UUID task ids and stored NULL intoken_usage(#712, #558). -
A bad GitHub PAT returned 401, which the web UI treated as session expiry and logged the user out; upstream GitHub 401s are now remapped to 400/502 with typed errors (#734).
-
cf initno longer runs a cloned repository'safter_inithook without a trust decision (#905). -
The default-
AUTH_SECRETwarning no longer prints on everycfcommand. -
Numerous correctness fixes across the conductor, PROOF9 ledger, CLI, task store and web UI — see the commit log for the full list.
- Coverage is enforced (#948).
.coveragercsetsfail_under = 80; the README badge and the contribution rule were corrected from an 88%/85% that nothing measured and that was not true (the real figure is 81.9%). uv run pytestis offline and free by default (#946).e2e_llmandlifecycleare deselected unless explicitly requested; collection no longer copies the repository'sANTHROPIC_API_KEYinto the process environment.scripts/lifecycle --mode api|webexits 3 instead of reporting success for stubs that only ever raisedNotImplementedError(#948).- Root documentation was brought back in line with the shipped product (#950).
- The cloud engine is experimental and gated (#966).
--engine cloud(E2B) now refuses to run unlessCODEFRAME_ENABLE_CLOUD_ENGINE=1is set, and it is gone fromcf engines list, the--enginehelp, the config validator's suggestions, and the docs that counted it as shipped. This breaks existing--engine cloudinvocations — set the variable to keep them working. E2B execution is out of launch scope and does not work end to end; the known defects are recorded underCODEFRAME_ENABLE_CLOUD_ENGINEinCLAUDE.mdas the checklist for lifting the gate.--isolation cloudwas never implemented and is unchanged.
0.9.1 - 2026-06-13
cf --version/cf -Vprints the installed version. (Note: withuv tool install, check the version viauv tool listorcf --version— the package is isolated, so a system Python'simportlib.metadatawill not see it.)TRADEMARKS.md— trademark policy clarifying that the AGPL covers the code, while the CodeFRAME name and logo are reserved trademarks (a fork may use the code but must rename).
- The default-
AUTH_SECRETwarning no longer prints on everycfcommand. It was emitted at import time and leaked onto the CLI (which never uses auth); the check now lives only in server startup validation, which still warns in self-hosted mode and fails hard in hosted mode.
- README marks the CodeFRAME™ trademark and links the new policy;
LICENSING.mdnotes the code/brand boundary.
0.9.0 - 2026-06-12
First public beta and the first release published to PyPI as
codeframe-ai. The codeframe name
on PyPI is taken by an unrelated package; a PEP 541
name claim is being pursued in parallel. The CLI entry point remains cf.
- PyPI distribution. Install with
uv tool install codeframe-ai,uvx codeframe-ai, orpipx install codeframe-ai. Bothcfandcodeframeconsole scripts are provided. - Release automation. Tag-triggered workflow builds with
uv buildand publishes to PyPI via trusted publishing (OIDC, no long-lived tokens). All actions are SHA-pinned. - Launch documentation.
SECURITY.md(private vulnerability reporting),LICENSING.md(plain-language AGPL-3.0 + commercial path), beta issue templates, and a refreshedCONTRIBUTING.md. - This
CHANGELOG.md.
- Packaging was incomplete. The wheel previously shipped only the top-level
codeframepackage (2 files), so an installedcffailed on import. Builds now include all subpackages and thetemplates/runtime data via setuptools auto-discovery. - Incorrect license metadata. Package metadata declared MIT; the project is and always has been AGPL-3.0. Metadata now matches the
LICENSEfile.
- Version bumped from a placeholder
0.1.0to an honest beta0.9.0; development status classifier moved to4 - Beta. - README installation section now leads with
uv tool installinstead of git-clone; status badge updated to beta with a stability statement.