Repository navigation
v0.23.0
Changed
npm run releasenow accepts a package up to 35 MB (was 20 MB): the Go port made the four native binaries about 15 MB each, so the 0.23.0 package is 28.3 MB; the refusal readspublished package must be under 35 MB(B605)block closeruns in Go for late and cap rows whose file, finding or open id is an object or array (Node's[object Object]and joined text, or Node'sarg.replaceAll is not a functionerror for a file it cannot quote) and for plain-text or Codex transcripts with JavaScript-only whitespace (NBSP, U+2028, BOM); before, these closes handed over to Node (close-gates-format, close-transcript-format). A routine close under aclose:routinegrant now prints Node'sopened beforewarning once per gate load and joins every routine failure into theclose-not-routinereason, byte-equal to Node (B590)block closeruns in Go when a changed file matchesreview.excludeor the default lock-file list: the file leaves the review set, gets agate.review_excludedrow and anot reviewedline, and an npm lock gets Node's lock check andlockfileblocker; before, every such close handed over to Node (close-excluded-file). A lock shape Go cannot judge like Node hands over with the new reason close-lockfile-format (B587)block closeruns in Go for a transcript that is not valid UTF-8 (decoded as Node does, each bad byte run one U+FFFD), a Claude Code log with an escaped surrogate pair, and agent waiver and reopen rows whose fields hold objects or arrays (--jsonprints them in the ledger line's key order); before, these closes handed over to Node (close-transcript-format, close-gates-format) (B583)- Go reads the Node version when it runs (
node --versiononce per process,CODE_FORGE_NODEelsenodeonPATH), not the build machine's: error-log rows, the gate reuse stamp and thelogs reportNode line match the node that runs;logs reportno longer hands over when no Node version is known and printsunknown(B585) factswith a Codex (openai) step in thelevels.L0ladder (first, as a fallback, or from a top-levelprovider: openai) now runs in Go byte-equal to Node instead of handing over: the read-onlycodex execcall in the snapshot, the packet on stdin, the OpenAI-strict schema file, the-oanswer, the fallback moves on usage limit, 401, 503, timeout and exit, the answer checks, the sheet and the ledger rows;review.allow_open_book_codexdoes not change it, as in Node (B582)- A fix-loop recheck with a block base runs in Go byte-equal to Node's packet builder for every peer case: one peer, several peers (named and imported kept, the rest dropped), a moved-code hint alone, a moved hint plus cross-file evidence, over the budget (the cut line, or no evidence), no peers and no base;
worker --run <id>serves such a recheck of a .js file end to end with no hand-over row (B564) block readyno longer hands over to Node when the workspace path holds secret-like text such aseyJ,AKIA,AIzaorsk-(a random temp folder name did this once on CI); like Node, it masks only the run's signer key, and output that would show that key still runs in Node (B565)- Go no longer needs a
nodeon PATH forcontext packandcloud-coder: with no Node, the pack's## code-forgeline names the install'sbin/code-forgelauncher instead of refusing (with Node found, the pack bytes are unchanged), andcloud-coderrunsreview-fileandledger add coderin this Go binary instead of the Node router (B572) - The Go binary is required:
bin/code-forgeno longer falls back to Node. With no binary for the platform and arch, a missing file or one without execute permission (and forsetup, a binary that crashes), it prints one stderr message with<platform>-<arch>, the expected path and the fix (sh <package>/scripts/install.sh, thennpm i -g @codedology/code-forgeif that fails) and exits 69, a code no verb uses;CODE_FORGE_NATIVE=0still runs the Node router. Newscripts/install.sh(POSIX sh, shipped) checks the binary for this OS and processor, restores a lost execute bit, runs--versionandinternal version, compares the version withpackage.jsonand prints OK or the problem and onefix:line (exit 0 / 1); no network, no sudo, nopostinstall(B569) npm run releaseruns no Node on the laptop: it builds the four native release targets withgo buildfrom Go (same targets, flags, temp name, mode and printed lines asscripts/build-native.mjs; the Node version stamp comes fromnode --versionwhen a node is usable and staysunknownotherwise), and in place of the localgen-config-doc --check,gen-commands-doc --check,npm testandnpm run typecheckit requires the latestCIrun for HEAD to be completed with success, refusing before any write with one line naming HEAD and the run state;npm pack --dry-run,npm ls --jsonandclaude plugin validate .still run; the--no-checkswarning names the new list and the notes usage line namessh scripts/cf-release.sh release notes(B580)- The Node release scripts are gone:
scripts/release.mjs,release-site.mjs,docs-block.mjsandchangelog.mjsand their Node tests are deleted, after every case those tests checked was ported to the Go tool's goldens (74 new multi-step cases recorded from Node); the GitHub release workflow sets up Go and writes the notes withsh scripts/cf-release.sh release notes(same bytes), andscripts/gen-site-data.mjsreads CHANGELOG sections itself with the same output; nothing changes in the npm package (B574) - The maintainer release tools run in Go:
npm run release,npm run release:site,npm run docs-blockandnpm run changelogbuild and runnative/cmd/cf-releasethroughscripts/cf-release.sh, with the same arguments, output, exit codes, file edits and git commands as the Node scripts, checked against goldens recorded from Node; the Node scripts stay because tests, the site data generator and the release workflow still use them, and nothing new ships in the npm package (B570) - The native daemon's
statusno longer starts a Node helper: a block id outside printable ASCII is answered in Go when it is the one listed block or sits on a closed or stopped block (also forstatusandnative-status); with two or more such listed blocks the daemon answersstatus-unreadable, as it did with no Node, and the status command computes the status itself (B576) - The native rebuild in
gates runandblock rebaserunsgo buildin Go instead ofnode scripts/build-native.mjs --host: same env, ldflags,<binary>.<pid>.tmptemp name, mode 755, rename andnative-rebuild-failedtext; it works with no Node on PATH, and then leaves the binary's Node version atunknown(B575) factschecks more glob path claims in Go, like Node'spath.matchesGlob: braces ({a,b},{1..3}), backslashes,[:ascii:]and[:xdigit:], extglob openers with no)and non-ASCII text with Node's case folding. A Unicode POSIX class, an extglob that can close, a case-insensitive suffix with a sigma, a Codex L0 step (B551 is not on this base) and the gate's non-ISO dates (Node reads them in the local time zone) still hand over before any write (B577)block rebasethat hands a narrow state to Node no longer prints an autopilot expiry warning twice: a failed grant expiry or an approval not restored yet is reported once, by Node's own check; a key or file read error in such a warning names no path, as Node's (B584)block rebaseno longer starts a Node child: active and due autopilot approvals, run records with no orphans list, an odd sibling block or an unreadable config snapshot, falsy or invalidrebase_checkvalues and a missingHOMErun in Go with Node's output, run record and ledger rows; the few states Go cannot read hand over with a narrow namedrebase-*reason before any write (B578)- The Go worker, the daemon (
internal serve) and every Go verb (review,block close,block land, gates, status, proof export and the rest) record each child they start in the run root's pid registry like Node's exec:pids/<pid>.jsonwhile it runs, the owner pid, start time and run id in its environment, the lazy root released at exit; stdout and exit codes do not change (B573) block openserves its former Node fallbacks in Go, byte-equal to Node: an emptyproof.worktree.dirorbase,--afterstatuses that are not text, claim rows whose path is not text, the signer key and ledger checks with no--level, brief loop, name-too-long and read errors, acceptance and pipeline YAML errors, pipeline and outcome read errors, noHOMEand block ids such as__proto__; YAML forms Go does not reproduce, AJV schema wording, a torn ledger line, a failed home lookup and an unresolvable brief path hand over before any write under the new reasonsopen-acceptance-yaml,open-pipeline-form,open-outcome-form,open-level-ledger,open-home-lookupandopen-brief-cwd; Go's ELOOP and ENAMETOOLONG texts are libuv's, as Node prints them (B581)- CI on Linux is green again: the tools and init rows follow a platform seam, so the init wizard test replays its Mac golden (Homebrew hints, Solo.app) on Linux too; the
block closefake reviewer writes its result file then renames it, like the worker, so close never reads a half-written result; the Jev triage test waits for its fake server before it reads the requests (the race detector caught the bare read); the 25 ms Go hand-over check reports its number on CI runners instead of failing, because the same binary measured 10 to 63 ms there, and local runs keep the gate (B560). - A Go worker that hands its run to Node keeps the queue served while Node starts: it leaves a hand-over announcement that
review-file --waitreads as live and Node's boot prunes, so a waiting review no longer endsworker_downduring the hand-over (B561) - Go
doctorrecords each child it starts (CLI probes, pings and probe sessions,gitandop read) in the run root's pid registry like Node, and Goinittakes the temp root from the config at process start as Node does, so atmp.rootfound from a subfolder still holds after init writes its own.code-forge.yml(B567) code-forge reviewof several files or of a test-like file runs in Go, byte-equal to Node, instead of handing the whole run to Node (review-worker-handoffis no longer used): the B561 hand-over announcement closed the race that made a waiting review readworker_down(B561b)- Go
tools,tools installand theinittool installs record each child in the run root's pid registry like Node (pids/<pid>.jsonwith pid, start time and command while it runs, removed when it ends), so a later sweep can stop an orphan; a registry that cannot be written never stops the probe or install (B563) - Go
logs reportrecords eachnpmandghchild in its run root's pid registry like Node (pids/<pid>.jsonwith pid, start time and command while the child runs, removed when it ends), so a later sweep can stop an orphan; a registry that cannot be written never stops the child (B559) - Tests give the same result on every machine: the doctor and tools rows no longer read this machine's
/Applications(a seam the tests point at an empty folder), the no-config doctor test seals PATH, the init wizard golden compares copied skill files with the repo'sskill/folder instead of a frozen copy, the B489 fake reviewer waits for its pid entry, and the Node gates tests expectgates detectandgates scopeto run in Go (since B459); no product change (B552) factsbuilds the facts sheet in Go, byte-equal to Node: the claim tokens, the read-only snapshot at HEAD with in-project--sources, the L0 facts session on anthropic or xai, the answer checks and downgrade lines, the sheet, the ledger rows, the breadcrumb and error log, and--run;spawn --role facts --cwdruns in Go too. A Codex L0 step, a glob path claim, a non-UTF-8 brief, a run root inside a git work tree and a--sourcespath outside the project keep narrow hand-overs decided before any write (B556)factsserves in Go, byte-equal to Node, the cases B556 handed over: glob path claims, a non-UTF-8--brief, a run root inside a git work tree,--sourcesoutside the project, and Node's crash for a config with nolevels.L0(same stderr, exit 1 and error-log row); the gate's Date.parse cases now hand over before any write. A Codex L0 step still hands over until B551 is on main (B568)factsrefuses in Go, like Node, before its session starts: a missing, unreadable or too-new.code-forge.yml, an unreadable--briefor--sourcespath, a bad--timeoutand a bad--runid give Node's stderr, exit 2, breadcrumb and error-log row with nothing written; a call that passes these checks still builds the sheet in Node (facts-session), and a YAML syntax error hands over asfacts-config(B555)logs report --no-aiwith matching errors runs in Go, byte-equal to Node: the npm version check, the built-in scrub, the secret check, the preview and--dry-run, theghsearch, comment and create with the label retry, and the prefilled link with the saved report whenghis missing or fails; the AI scrub,--with-doctor, a known-fixes table, an unknown system and a terminal prompt still hand over to Node with named reasons (B554)author,s2andjev askrun in Go, byte-equal to Node:authorands2on anthropic and xai levels (prompt, provider argv, schema check, draft or answer, ledger rows, refusals),jev askwith--rulesand with Jev (request, retries, failure lines, decision bands,decisionrow, refusals) using the env or file-store key; an openai (Codex) level, the keychain or 1Password key, YAML syntax errors and inputs Node words differently hand over before any session or write, each with its own reason (B550)reviewof one file runs in Go, byte-equal to Node: config,--acceptance/--intent,--runreuse, run start, the review block, the ticket and its wait, block stop, run end, the worker reap, the fix list, totals,--json, exit codes and signals. Several files or a test-like file, and state Go cannot read like Node, keep narrow named hand-overs decided before anything is written (B553)- Go tests no longer fail on a loaded machine where they waited on a short fixed clock: the
block closefake reviewer waits until close returns (30 s safety bound) instead of 2 s, and the run start worker-stop, file lock FIFO, test slot admission and leaked-pipe gate waits get long bounds that still end as soon as the awaited event happens; no product change (B539) - The Go worker reviews light blocks (the batch round), Markdown files section by section, dual lenses with the L3 judge and consensus review, and recovers the recheck session (second level, its ladder, the L2 ladder retry, routes) like Node, byte-equal, instead of handing the ticket to Node; an L2 ladder entry with no provider routes like Node; a judge with no
levels.L3, a light round after the cap with peer files, a surrogate-cutting Markdown heading and an adaptive pick of a no-provider entry still hand over with nothing written (B545) initruns its steps after the write in Go, byte-equal to Node: the Jev key fromCODE_FORGE_KEY_JEVor the file key store (with the 24 h expiry cap and expired-entry removal),--tools recommendedand--yes-toolinstalls,--refresh-models, and the quick doctor (its rows, JSON summary and exit 1 on a FAIL). The keychain key path stays on Node with the new narrow reasoninit-jev-keychain, and a doctor that would hand over makes init hand over before it writes anything (B548)spawn --role coder,--role factsand--backgroundrun in Go, byte-equal to Node: the coder prompt with--blockand the run's block brief and acceptance lines, thesentinelresult field, the--runcoder.sandboxcheck, the facts session and the detached background start with its logs and pid files; a Codex step, facts with--cwd, a run record Go cannot read like Node and a background CLI that is not found still hand over with their own reasons (B549)- The skill's
forge <verb>shim now runs the package'sbin/code-forgesh launcher (Go binary first, Node router withCODE_FORGE_NATIVE=0or no Go binary) instead of always the Node routerbin/code-forge.mjs, so skill verbs ported to Go run in Go;CODE_FORGE_BINnaming the launcher, or acode-forge.mjswith the launcher next to it, also goes through the launcher, while otherCODE_FORGE_BINfiles and old installs with onlybin/code-forge.mjskeep running in Node (B547) - Codex (openai) sessions run in Go where
review.allow_open_book_codex: truelets them:spawnreviewer, judge, s2 and author steps and the worker's ticket review on an openai level, with Node'scodex execargv, stdin packet, OpenAI-strict schema file,-oanswer file, usage and cost rows, null drop andpassedcoerce, error events (usage limit retries, login expired, at capacity), timeout and exit codes, byte-equal to Node; an effort the codex builder refuses or a schema strict mode changes stays with Node, and doctor's Codex pings, isolation and path-deny still hand over (B551) spawn --role coderon an openai (Codex) step runs in Go, foreground and--background, byte-equal to Node: Node'scodex exec -s workspace-writeargv, a freshCODEX_HOMEper session under the run root'scodex-homes/, the answer and sentinel read from the-ofile andoutPathinpid.json; the facts role on openai runs in Go too. Only a Codex coder step withcoder.sandboxset still goes to Node (spawn-codex-sandbox) (B551r)doctorwith a valid config finishes the probes' I/O errors in Go like Node instead of handing over after the probes started: an unwritable temp root gives Node'sprobes: no temp rootrow, a session that cannot start gives Node'serror(<code>)rows, an unwritable prompt file, temp repo or canary ends with Node'sverb "doctor" failedline and exit 1, and an errno Node has no name for prints Node'sUnknown system error -<n>instead ofUNKNOWN(B535)initat a terminal runs its wizard in Go: every prompt with its text, default, choices, keys and re-ask on a bad answer, the summary, the gates and proof choice and the apply confirm, then the B527 setup; terminal output, files, the init log and exit codes (cancel 1, end of input 13 with Node's warning) are byte-equal to Node in a pseudo-terminal; a terminal Go does not draw like Node,--yes-tool, the Jev key store, the doctor and preset shapes the wizard shows differently hand over before the first prompt (B528)- The Go worker builds the whole review packet itself, byte-equal to Node: related files and definitions with the import-header context, the deletion note, the test-quality hint and moved-code hints with peer files (also in Markdown sections, the dual-lens judge packet and a light round after the cap); a recheck under
review.recheck_scope: fileand a recheck with moved-code hints and cross-file evidence from the block's other changed files run in Go too, so these tickets no longer hand over to Node (B537) doctorwith a valid config runs in Go, text and--json, byte-equal to Node: the Jev live call, the provider CLI rows, the role pings, isolation, path deny, Codex rules and the worker and signer probe join the local rows; every case Go cannot serve is decided before the first probe, so a hand-over writes nothing. A worker registry Go cannot judge hands over after the probe cleans up, an errno outside Go's table printsUNKNOWNlike Node, and one pid registry writer serves sessions and the doctor (B525)- The Go worker serves runs with a Jev key: it resolves the key at boot like Node (env variable, file store, 1Password cache) instead of handing the whole worker to Node, and the review asks System 1 (Jev) like Node, byte-equal:
defecttriage in full rounds and on late findings,resolvedclosing open findings before the recheck session, the request, retries, timeouts, failure kinds, thereview.triagerows withsource,pandband, and thes1_fallbackwarning; a key in the OS keychain, a store Go cannot read back or a live 1Password read, and a bad key reference still hand over with their own reasons (worker-jev-keychain,worker-jev-key-store,worker-jev-key-ref) (B533) - The Go worker runs the commit watch (
review.file_loop: watch) instead of handing the whole worker to Node: the 15 s quiet wait and 120 s burst limit, one ticket per owned changed file hashed from git objects, thewatch.skipped/watch.heldrows, superseded markers and the watch cursor, byte-equal to Node; a watch shape Go cannot reproduce stops the Go worker before that tick writes (worker-watch-shape) (B534) autopilot askruns the delegate session in Go when the grant lets the question through, andautopilot approvewrites the.code-forge.ymlchange, reloads the run and signs theautopilot.approverow in Go, byte-equal to Node; a due approval of an active run is put back and reloaded in Go too. Shapes Go does not reproduce keep a narrow hand-over decided before any write (B536)- The Go worker's review recovers like Node instead of handing the ticket to Node: the
levels.L2fallback ladder,review.routesrecovery andreview.second_levels, with Node's rows, warnings and session configs byte-equal, and the timeout fallback picks among ladder, second-level and route entries like Node; malformed shapes and the recheck session's recovery still hand over (B538) init --no-interaction(and init with no terminal) sets the project up in Go, byte-equal to Node: gate and proof detection, the settings summary, the merge with an existing.code-forge.yml, the config checks, the.code-forge.ymlwrite with theyamlpackage's exact bytes, skill links andinstalls.json, the user config, the engine stop text, the init log and the agent JSON line; a Jev key read, a 1Password item,--tools recommended,--refresh-models, the doctor, links Go cannot place, configs Go cannot rebuild or check and an unreadable user config hand over before any write, each with its own reason (B527)- Tests can no longer stop a process of the person running them: every signal to a pid from the process table or a run record (the
run start/sweepprocess sweep,run endand the launched-worker stop, the Go worker's orphan sweep, the gates' and sessions' leftover group members) goes through one guard that, insidego test, in a binary a test builds, or withCODE_FORGE_TEST_SIGNAL_ROOTset, sends a real signal only to descendants of the test and answers EPERM otherwise; without them nothing changes.doctorcounts a.nanlevel value as unset, as Node does (B529) - The doctor's worker and signer probe has a Go part, not wired into the full run yet: the throwaway run and repository, the
signer key,workerandsignerrows byte-equal to Node (worker announced and stopped on SIGTERM, a worker that never announces, one that ignores SIGTERM, a failed sign/verify round trip, a git or config copy failure), and the run, key, lock, pid entry and temp root removed afterwards;run startshares its record and locked create with it (B524) initserves in Go, byte-equal to Node, every usage error, noHOME, a.code-forge.ymlthat cannot be loaded (read-error,migrate-error, a root that is not a mapping) and the draft-PR refusal without--coder-may-push yes, with the init log, the agent JSON line, the breadcrumb and the error log; the rest of the wizard hands over before Go writes anything, each with its own reason (init-interactive,init-setup,init-jev-link,init-arg-encoding,init-config-syntax,init-answers,init-output) (B502)- Plain
run startandrun start --add-workerlaunch this binary's Go worker (code-forge worker --run <id>) and pin its pid, so they no longer need Node or hand over when no Node is found; a run the Go worker does not serve still becomes the Node worker in the same process, and the process sweep now also stops a Go worker of a finished run (B511) - The hand-over reason list (the
handoverReasonconstants and thehandoverReasonsarray) moved unchanged fromhandover_log.goto its own filenative/cmd/code-forge-native/handover_reasons.go, and.gitattributesnow marks only that filemerge=union, so a union merge can no longer garble the hand-over functions; a Go test checks every reason has one non-empty, unique code (B513) native-status, the private daemon helper, runs in Go with the same status lines, line splitting, router error line, exit 1, breadcrumb and error log as Node, and--help/-hprint its usage; noHOME, a terminal stderr with no agent, and a line Go cannot read exactly like Node (a non-ASCII block id to sort, anInfinitynumber, a lone surrogate, bytes that are not UTF-8) still hand over to Node with their own reason (B501)- The native daemon answers
statusin Go where it used to start Node'snative-statushelper: a run record or ledger row Node cannot read givesstatus-unreadable, and a spend that overflows isnull, with the same gate timeout and flaky details; only a block id outside printable ASCII still uses the helper (B503) - Go has the doctor's Jev client (Node's request, retries, 30 s attempts and failure kinds), its
jevrow and the provider CLIcli/flagsrows; the full doctor run still hands over to Node asdoctor-live-probesuntil the model-call, isolation, path-deny, Codex rules and worker probes run in Go (B505) - The full
doctorrun with no.code-forge.ymlruns in Go (text and--json) with Node's rows, exit code, summary and error log: tools, ledger, locks and worker registry, tmp roots, the read-only process sweep and memory rows, review state, review concurrency, probes skipped, signer, native binary and native daemon; Go functions for the gate command, coder sandbox and darwin worktree-indexing rows match Node's; a config that loads but fails validation (doctor-full-invalid-config), a live project worker (doctor-full-live-worker), a worker registry Go cannot judge, another native binary and an unreadable review-state record still hand over to Node with their own reasons (B504) - Go has the doctor's model-call probes with Node's rows: the role pings (facts, coder, reviewer, s2, delegate) on anthropic and xai with the same argv, budget, timeout, schemas and rate-limit retries, and the isolation, path-deny and Codex rules probes; Codex sessions and config shapes Go does not reproduce stay with Node, and the full doctor run still hands over as
doctor-live-probesuntil the doctor calls them (B523)
Added
block accept-hit,block amend-acceptance,block unwaive,block ack-waiversandblock attemptrun in Go with Node's terminal question, refusals, signed ledger rows, registry changes and text or JSON output;block waiveat a terminal asks and signs the human waiver in Go; the--yesjudge andblock reopenat a terminal still hand over to Node (B453)block closeruns in Go for an ack digest in Node's LatinlocaleCompareorder, an object or arraydecision(Node's key order), V8Date.parserollover and 2-digit date forms, and late or cap rows whose file is empty, a number or false or whose finding is missing or not text; on a shared terminal its stderr lines (auto-claim, WARN, refusal summary) come before the stdout result as in Node, and--auto-claimclaims before a later transcript or--worker-pidrefusal as Node does; non-Latin ack digests, object or array late/cap values and out-of-range legacy dates still hand over (B498)block close --auto-claimruns in Go on a run with an autopilot record and withclose.require_humanat a terminal (same prompt text and answers; a cancel records nothing); a transcript that runs thehooks.on_block_endcommand is Node'srule_breakin Goblock readyandblock close(Go close skipped this check before and closed where Node refuses); late findings with no file, legacytoUTCString/toStringreview dates and non-ASCII ack digests run in Go; an object decision, an unknown date form and an order-dependent ack digest still hand over to Node with their own reason (B493)block closerefuses a malformed, missing, not-a-directory, other-branch or foreign block worktree and one without the run's workspace directory in Go with Node's messages, reads ledger null and scalar rows and an unreadable rotated ledger file like Node, and reads the ledger before the run-ended check;block open --briefprints Node's realpath and read errors;block stopwith a daemon socket runs in Go and its done file takes the serving daemon's rows;block landprints Node's read error for a run file it cannot read (B470).keys list,keys set --cache-hours,keys testandkeys remove(file key store),report --slug(text,--json,--export, all 18 sections) anddoctor --helprun in Go with the same output, exit codes and files as Node; 1Password and keychain writes, a typedkeys set, every doctor check run and ledger rows whose bytes depend on JavaScript coercion still hand over to Node (B456)ledger calibration,ledger outcome(--pr/--ciand--scan-git),ledger add coderandledger outside-reviewrun in Go with Node's output, exit codes, signed rows and error-log entries;logs clear(no log,--yes, no-terminal refusal),logs reportwith nothing to report, andlogshelp, unknown subcommands and usage errors run in Go; the clear prompt on a terminal and a report that would file an issue hand over to Node with their own reasons (B457)- Go review plays a
needs_fileanswer (the file round with attached files), a schema miss (the signedreview.schema_invalidrow with its diagnosis) and a second same-model timeout (the ledger-confirmed fallback reviewer) like Node instead of recording them asunavailable(B514) - The Go worker plays the recheck and patch-check rounds and reopens a cap stop or a split stop when the config is raised, like Node, instead of handing the ticket over (B517)
- Go
worker --run <id>serves the queue: boot, registry, heartbeat, run root, ticket reviews, orphan sweep, idle exit and a clean stop on SIGINT/SIGTERM, with--once; it gives the whole worker to Node for a Jev key, the commit watch, no config snapshot and on the first ticket Go cannot review, so no ticket is lost or reviewed twice (B489) - Go worker serves the other worktree codes, Node's one config-read retry and the
worker-errorresult for an I/O error (with the routingdetail) byte-equal to Node, so those tickets no longer go to Node (B507) - Go
worker.TicketRunner.RunTicketnow reviews a ticket end to end when a dry pass finds every part ported (rules risk, block kind, acceptance facts, rules digest orcontext-unreadable, owned/changed/test files, paired test context, one fix-loop round with one L2 session): rows, review state, signed result, timings and done marker (now withopen_findings) are byte-equal to Node on the same repo and fake reviewer CLI; anything else stays unsupported with nothing written andworkerstill hands over (B497) - Go
worker.FixLoopRoundwraps one fix-loop round like Node'sfixLoopRound(block lock, once-per-blockreview.budgetrow, state load with tampered / lost / restored / legacy move, L3 rung,hash-movedapproval check, crash saved as retry, outcomesapproval-not-written,findings-open,no-fix-hunks), byte-equal to Node goldens; tickets needing reopen rows, extra rounds, rechecks or patch checks stay unsupported with nothing written, and the worker does not call it yet (B496) - Go
review.RunRound,review.BudgetRows/review.RulesRiskandworker.SaveStateport the worker's full fix-loop round, block budget rows and signed review state byte-equal to Node (golden tests over Node's own output); tests pinpickReviewerexploration and strict date parsing to Node; the worker does not call them yet and still returns unsupported for review sessions (B495) - Go
worker.TicketRunner.RunTicketroutes a ticket like Node (review.routes, adaptive L2 routing from the ledger, signedreview.routerows,route-invalidandroute-row) and serves the engine's first refusals (review.exclude, unreadable run record, unknown block, missing base, malformed worktree, amended acceptance), byte-equal to Node; tickets that need a review session still return unsupported with nothing written, andworkerstill hands over (B492) - Go
native/workerruns one ticket's refusal outcomes (TicketRunner.RunTicket): bad ticket, bad path, other run, stale or missing file, worktree mismatch, unreadable file, gone or malformed worktree, unreadable run record and missing config snapshot, with Node's file lock, signed result, ticket timings, done marker, signedreview.resultrow and poison rule, byte-equal to Node; tickets that need a review (routing, risk and facts, fix loop) return unsupported with nothing written, andworkerstill hands over (B488) - Go package
native/workerholds the review worker's boot and ticket pool (boot lock, registry admission, pins and the signedworker.reattachrow, announce and heartbeat files byte-equal to Node, clean stop, queue order, Node's ticket claim lock,parallel_tickets,provider_parallelandfair_share); the per-ticket review is not ported yet, soworkerstill hands the queue over to Node (B485) spawn --run <id>runs in Go for the roles Go serves without--run: the run's temp root, then the run-pinnedbudget.usdand autopilot category gate before each step (Go packagenative/session), with the same refusals, stderr, exit 3,budget.refused,budget.warningand signedautopilot.pauserows, saved pause and error-log warning as Node;--runwith the coder role and--backgroundstill hand over (B482)spawnruns a foreground closed-book session in Go (Go packagenative/session: argv, fallback ladder, rate-limit retries, hard and silence timeouts, pid registry, answer and usage parsing, the ledger row) for the reviewer, judge, s2, author and delegate roles on anthropic and xai steps with no schema or the finding schema, and--print-argv, with Node's stdout, stderr, exit code and row;--run,--background, the coder and facts roles and other schemas still hand over to Node;review.Deps.Spawncan now run on this session (B477)- Go can review one ticket on the single-reviewer path (
native/review: packet, one L2 session through a spawn seam with the same-model timeout retry, the stub guard, thereview.plan,review.unavailableandreview.session_timeoutrows and Node's result object), equal to Node on 25 tickets; a case it does not cover is refused before a session starts, or stops with a gap error when it shows only after the session (needs_file, a second same-model timeout, a schema miss with a ledger), and thereviewverb still hands over to Node until B477 wires it (B476) worker,spawnandreviewrun in Go for help, usage errors, unknown flags and the refusals Node makes before work starts (a bad or ended run forworker; config,--timeout,--schema, run id, level and role forspawn; no repository, a bad base or--filespath forreview), andreviewwith nothing left to review runs fully in Go (text and--json, with the skipped-file notes); serving the queue, the session and a review run with files still hand over to Node with their own reasons (B460)autopilot binnacle,autopilot log,autopilot round,autopilot level, the start prompt at a terminal without--yes, andautopilot statusandautopilot stopfor a grant with no link (the binnacle files) run in Go with the same output, exit codes, files and signedautopilot.extra_roundandautopilot.levelrows as Node;ask,waive,approveand runs with active approvals still hand over to Node with their own reason (B478)- A due autopilot approval of an ended run now puts the old value back in
.code-forge.ymlin Go, with the same bytes theyamlpackage writes (comments, blank lines, quoting, flow and block lists, document markers, CRLF), the file's mode kept and Node's WARN lines for a parent that is not a mapping or a failed write; YAML shapes Go does not write byte for byte still hand over to Node (B494) autopilot approveat a terminal (the owner's prompt with clack's wrapping, the cancel text, a failed prompt and the refusals that come after the answer without a config change) and a due approval that needs no.code-forge.ymlwrite or run reload (a pending signed row, a value changed by hand, an ended run that already holds the old value, a missing or unreadable config) run in Go with the same output, exit codes, records and signed rows as Node; an approve that changes the config, a due approval of an active run or one that writes the old value back, and config text Go reads differently still hand over to Node with their own reason (B490)autopilot ask(every refusal before the delegate session, in text and--json, with the signedautopilot.expirerow of an expired grant),autopilot approve(every input check and the no-terminal refusal) and runs with active approvals that are not due run in Go with the same output, exit codes, records and rows as Node;askwith a grant that lets the question through,approveat a terminal, a due approval (autopilot-restore) andwaivestill hand over to Node (B484)autopilot binnacle,autopilot log,autopilot round,autopilot level, the start prompt at a terminal without--yes, andautopilot statusandautopilot stopfor a grant with no link (the binnacle files) run in Go with the same output, exit codes, files and signedautopilot.extra_roundandautopilot.levelrows as Node, and mask the run's signer key in output and binnacle files at the same points as Node;ask,waive,approveand runs with active approvals still hand over to Node with their own reason (B478)autopilot status,autopilot stopandautopilot start(with--yesor with no terminal) run in Go with the same output, exit codes, run record and signedautopilot.grant,autopilot.stopandautopilot.expirerows as Node, as doautopilothelp, usage errors, unknown flags and theapprove --yesrefusal; the start prompt at a terminal,ask,waive,round,level,approve,binnacle,logand grants with no link still hand over to Node with their own reason (B461)proof red-greenruns in Go with the same output, exit codes, export tree, lock, journal and signedexportandred-greenrows as Node, andproofcounts every project config rule in Go, includingproof.runners,review.routesunder multimodel andcoder.sandbox.add_dirs, and loads the config without the merge-gate check as Node does; a red-green that uses aproof.runnersentry or the Pest default, has a snapshot Go cannot read, or meets another error before the export still hands over to Node with its own reason (proof-runner,proof-snapshot,proof-red-green) (B481)proof lock,unlock,restore,export(also--remove) andproof tierwith a project config run in Go with the same output, exit codes, run record, lock, journal, export tree and signed ledger rows as Node;proof red-greenand the config rules Go does not check yet (review.routesunder multimodel,coder.sandbox.add_dirs,proof.runners, aschemamerge gate) still hand over to Node with their own reason (B462)help,versionand the--help/-h, usage errors and unknown flags ofinit,native-status,facts,author,s2,jevandproofrun in Go with the same output, exit codes, breadcrumb and error log as Node, as doproof baseline,proof tierwithout a project config and thejev askandproofargument checks; model sessions, the init wizard,native-status,jev askpast--state,proof tierwith a config and theproofrun work still hand over to Node with their own reason (B458)gates detect,gates secret-scan,gates safe-edit,gates scope,gates acceptanceandgates transcript-greprun in Go with the same output, exit codes, error rows and breadcrumbs as Node, as dogateshelp and usage errors;gates run --helpnow prints the usage instead of running the gates; the cases Go cannot match exactly hand over to Node with their own named reason;gates detecttreats a prettier dependency set to 0 as absent, as Node does (B459)code-forge sweepruns in Go: help, usage errors, the dry run (text and--json, idle workers included) and--applygive Node's output, exit codes, logs and signals; noHOME, an unreadable temp base and an idle check Go cannot judge still hand over to Node (B486)run startstops in Go what Node's process sweep stops (a worker of a finished run, an orphan whose owner is gone, a registered child of a dead temp root) with Node's checks and signals, andrun startandrun reloadreport a duplicate key or an unresolved tag in.code-forge.ymlin Go with Node's text; arun reloadof a config that loads, other YAML syntax errors andrun startwithout Node keep the Node hand-over (B472)- A plain
run start(config snapshot and hash, run record, key, mirror, signed rows, dead temp root removal, worker launch and pin),run start --add-workerand therun reloadrefusals run in Go with Node's output, exit codes, files and rows; a process sweep that would stop a process, a YAML syntax error and arun reloadof a config that loads still hand over to Node (B468) run status,run endandrun start --reattach(with or without--worker-pid) run in Go with the same output, exit codes, run record, mirror and signed ledger rows as Node, as dorunhelp, usage errors and unknown flags; a plainrun start,run start --add-workerandrun reloadstill hand over to Node with their own reason (B454)block closeandblock readyread Codexexec --jsontranscripts and decide thecode-forge-reviews-writerule in Go with Node's hits, an unreadable--transcriptprints Node's error and exits 1 in Go, and review dates in every ECMAScript date-time form are read like V8; hand-made late/cap rows with no file, object decisions, non-ASCII ack digests and the open, claim, stop and land edge cases still hand over to Node (B466)- The full
doctorrun still hands over to Node, but its hand-over now says why:doctor-live-probesfor a valid config (live Jev call, provider model probes, worker start and stop),doctor-full-no-configwhen no valid config loads (the process sweep, tmp-root and worker-registry checks are not in Go yet), anddoctor-full-runonly for a config Go cannot judge (B487) doctor --quicknow refreshes the cached Jev key in Go like Node: an expired file-store entry is deleted with its index row, an entry kept longer thankeys.cache_hoursis cut (entry and index row rewritten), and anop://reference is read withop read(one retry after a first-call timeout, logged as anop_retrywarning) and cached with its index row, with Node's 1Password reasons; only an index Go cannot read exactly like Node still hands over (doctor-key-refresh), and the full run stays in Node (doctor-full-run) (B483)doctor --quickruns in Go with Node's text,--json, masking and exit codes: config, harness links, Jev key (env or file store) and reviewer rows;doctorhelp, usage errors and unknown flags too; the full run, the keychain store, a key refresh or 1Password read, schema errors, secret-shaped values, sandbox dirs and ledger rows Go cannot read exactly still hand over to Node with their own reasons (B474)run reloadof a config that loads runs in Go with Node's output, exit codes, run record, mirror, ticket pins and signedrun.reloadrow under the run lock, inside the onerunrouter; YAML syntax errors, schema errors, secret-shaped values, sandbox dirs,!!tags and odd record shapes keep their own named hand-overs (B473, landed by B491)plan check(facts, slug, config caps and budget, ledger lanes, claims, overlaps, cycles, imports) andupgradere-pointing recorded installs run in Go with Node's output, exit codes and installs file; odd cases keep their own named hand-overs (B475)validateand signing a passingoutcome recordrun in Go with Node's output, exit codes and signed row;plan check,sweepandupgradeanswer help, usage errors and bad files in Go, while the plan check itself, the process scan and re-pointing installs still hand over to Node with their own reasons; schema errors, secret-shaped values and sandbox dirs invalidatehand over too (B471)resolve,models,list,remove,pipeline status|next,outcome seal|check(and the check part ofoutcome record) andtools [install]run in Go with Node's output, exit codes and files, including help, usage errors and unknown flags; YAML syntax errors, schema errors, files Go cannot write, signing a passingoutcome recordand thetools installyes prompt still hand over to Node;validate,plan check,sweepandupgradestill run in Node (B455)- Go prints the router's once-a-day error-log hint on a terminal (and keeps
~/.code-forge/logs/hints.json) for the verbs it serves, soledgerno longer hands a failure over for it;logs clearasks its confirm prompt in Go;pipeline status|nextreports outcome files it cannot read (for example a folder) in Go; a hint state Go cannot judge hands over asrouter-hint-state(B500)
Fixed
- The worker's daemon (
internal serve) no longer leaves itsproc-<pid>-<ms>temp root behind when it gets two stop signals: a stop of the worker's process group sends one and the worker's daemon stop a second, which killed the daemon after its first signal handler ended and before it removed the root (seen on Linux CI, where the daemon socket path fits); the daemon now keeps SIGTERM and SIGINT handled until it exits and stops without listening when a signal comes during its start (B602) logs report --no-aiwith a long folder path in an error message (such as a temp scratchpad path) gives the same result in Go and Node: both refuse it as a high-entropy string at the same report line, exit 1, unless the cleaning turns the whole long part into~or<project>; the earlier report of Node refusing while Go printed came from two different error logs, not from the code (B588)- Issue #36:
block rebasediffs merges on main against their first parent only, so a feature branch cut before main changed an owned file no longer reports that file asupstream_owned(or, with--accept-changed, as a falseowned-conflict); a batchblock landmerge gate now linksgates.merge_gate_links, runsgates.merge_gate_setupand honours--copy-links; a retry of a closed block under active autopilot approvals stays in Go instead of Node'sblock is closed, not open;native/README.mdnames theinternal block-rebase-landedhelper with its prefix (B589) - Go
doctorhands a worker registry it cannot judge to Node only after its probe worker is gone: the strict launch now waits (at most 2 s, like Node's stop after SIGKILL) until the killed worker is reaped, so no live or zombie worker pid is left behind on a loaded machine (B593) block landandreview-file --wait-blockno longer stop at the join with "reviews did not finish" on a busy machine: a git helper that exited 0 counted as failed when its output pipes were read more than 50 ms after it exited (exec.ErrWaitDelay); the pipe grace is now 2 s. The doctor golden tests read a sealed process table, so a zombie of another program on the machine no longer changes theirsweeprow (B544)- CI fixes for the red main runs: the Go job installs the npm packages (
npm ci, Node 24, npm cache) so the Go parity tests can run the Node reference, and 12 Node tests now expect what moved to Go (--version,logs clear/emptylogs report/noHOME, ledger calibration/outcome/add/outside-review, an unreadable land transcript), copy every native package the config imports into their fixtures, measure the hand-over budget on a verb that still hands over, and size the npm package for the host binary only (B541) code-forge setup(alsonpm run setupand the npmpostinstall) checks the Go binary for this OS and processor: restores lost execute bits, comparesinternal versionwith the package version, prints one OK line or the problem plus onefix:line (exit 1); the postinstall form only warns and exits 0 (B463)- A Go panic in a goroutine a command starts (the gates
block landruns next to its review wait,gates run's gate wait and output copies, the daemon, signal forwarders) follows the main-goroutine rules: a read-only command goes to Node with ago-panicrow, any other command prints one line, writes ago-panic-stoppedrow and exits 1, never exit 2 with a stack trace; the panic line also reaches the terminal forgates,block landandblock rebase, whose stderr is copied through the heal pipe (B509) - A Go panic no longer looks like a usage error (exit 2 with a stack trace): a read-only command (
setup,status,run status,queue status,heal list/show,decisions list,docs path,logs,logs summary/path/handovers,ledger tail) goes to Node with ago-panichand-over row; any other command is not re-run, prints one line naming the command and code site (never the panic text or arguments), writes ago-panic-stoppedrow and exits 1; a panic in a background goroutine still exits 2 (B508) code-forge setup(alsonpm run setup) checks the Go binary for this OS and processor: restores lost execute bits, compares the binary's version with the package version, prints one OK line or the problem plus onefix:line (exit 1); the Go binary serves it, and the entry hands it to Node'sscripts/setup.mjswhen the binary is missing, not executable or crashes; npm runs no install script (nopostinstall), so afternpm install -g @codedology/code-forgeruncode-forge setup(B463)
npm: https://www.npmjs.com/package/@codedology/code-forge/v/0.23.0
Full changelog: https://github.com/ricardov03/code-forge/blob/v0.23.0/CHANGELOG.md