You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Added
check_release_cadence in scripts/check_docs.py: the docs check fails when two milestones that docs/PRODUCT_MODE.md calls done are named only under [Unreleased] (I-086: M8 to M10 waited two weeks behind v0.5.0); CONTRIBUTING gains the release-after-every-milestone step and a merged-on-GitHub check before any post-merge step (I-087).
M10 live milestone on the Claude Code backend: notes_service (TypeScript, node:http plus zod) bootstrapped by scio new (the planner chose node-ts from the stack menu) and built through M1 (three features, one advisor escalation, npm install through the install phase, eslint, tsc typecheck and build, npm audit and black-box acceptance all green, merged locally), $4.61 estimated, nothing billed; the done criterion of issue #51 holds on the Fake and live. Open: the install phase leaves package.json and package-lock.json changes uncommitted (I-085).
M10 Second stack (issue #51, ADR 0014): a node-ts toolchain profile (configs/profiles/node-ts.yaml, TAP parsers in scio/toolchain/node_ts.py): Node 22 runs TypeScript directly, node --test is the runner, tsc, eslint and npm audit the quality bar (skipped while absent), npm install the install phase; one data-driven ProfileToolchain loaded from yaml with a StackParsers set per stack; protocol members for the product path (acceptance_dir, skeleton_command, command_words, app_target, syntax_check_argv, health_probe_argv, detect); Runtime generalised (env_dir, env_marker, optional create step and interpreter); profile detection from marker files (Settings.toolchain=auto is the default, RunContext.adopt_toolchain on the clone, the product load and the bootstrap); a node-ts scaffold (TypeScript walking skeleton with node:test smoke and acceptance tests, eslint flat config, CI with setup-node); the normaliser, acceptance runner, run_app, tool descriptions and Claude Code allow-rules speak the profile's language; the toolbox context's toolchain reaches edit_file and run_tests, and edit_file runs the profile's syntax check (module.stripTypeScriptTypes for TypeScript, I-083); planner prompt v2 lists the available stacks; resolve_command finds npm's .cmd shims on Windows (I-081). The Fake todo_api spec builds its first milestone in Python and in TypeScript (test_same_spec_builds_in_both_stacks); CI installs Node 22 for the Node-dependent tests.
M9 (issue #49), first slices: delete_file tool on every sandbox backend (Sandbox.delete; the coder and debugger have it; a new file rejected by the edit lint gate is now removed instead of left empty); the python profile declares a quality bar (checks: coverage with an 80% floor, wheel build, dependency audit) that integrate runs after the suite and lint, reporting a check whose tool is absent as skipped and failing the milestone on a real failure; coverage artifacts added to the profile's cache excludes; the Claude Code worker backend now refuses a non-local sandbox.
M9 runtime (ADR 0013): a per-product environment (.scio/sandbox/venv, a plain venv with SCIO's own environment linked through a .pth file on a local sandbox, the profile's test_tools installed on any other, I-074) created by the install phase with the network open for that call only (Sandbox.exec(network=True)) and the approved dependencies from PRODUCT.md installed; install_deps worker tool gated by that list (an unapproved package is refused with the escalation hint; context-aware tools via ToolDef.needs_context / ToolBox.context); run_app starts python -m <module>, waits for a local health URL or the exit, and stops it (local sandbox only); the python profile's runtime: block.
M9 live milestone on the Claude Code backend: bookmarks_api (http.server plus pyyaml) bootstrapped by scio new and built through M1 (four features, one advisor escalation, black-box acceptance against the started server, coverage passed, merged locally), $5.38 estimated, nothing billed; the done criterion of issue #49 holds on the Fake and live.
M9 Docker default (ADR 0013 decision 10): scio build runs in Docker when a daemon answers and the docker/sandbox.Dockerfile image (Python plus git) is there, and in the local sandbox otherwise or on the Claude Code worker backend, with the first ledger line saying which and what a local sandbox does not enforce (SCIO_PRODUCT_SANDBOX_BACKEND=auto|local|docker). DockerSandbox is one persistent container per sandbox on an internal network (no route out), python rewritten to the product environment, a timeout inside the container keeping it; exec(network=True) attaches an egress-proxy sidecar (scio/aci/sandbox/egress_proxy.py, CONNECT-only, Limits.network_allowlist) for the duration of the call, so the install phase reaches the registry hosts and nothing else. run_acceptance starts an http product inside a non-local sandbox and probes it from inside. CI gains the docker-live job that exercises all of it on the runner's daemon.
M9 acceptance (ADR 0013): PRODUCT.md gains a ## Runtime section (kind: cli|http, module, start arguments with {port}, health path) that the product planner fills and the normaliser checks; the scaffold ships tests/acceptance/ (black-box: a subprocess for a CLI, the health endpoint for an http product, which the scaffold now serves with serve --port); integrate starts an http product on a free port, runs the acceptance tests with APP_URL, stops it, and reports [acceptance] beside the other checks. The scripted Fake product todo_api (an http server with pyyaml on its approved list) runs through the whole milestone loop offline: install phase, two features, server started for the black-box tests, merge. The scaffold's test directories are packages, so unit and acceptance tests may share basenames (I-073).
Claude Code backend (ADR 0012, issue #47): SCIO's model work can run through the unmodified claude binary on the owner's Claude subscription instead of the Messages API. SCIO_PROVIDER_OVERRIDE=claude_code sends every tool-less role through ClaudeCodeProvider (one restricted, tool-less claude -p per call, --json-schema for structured outputs); SCIO_WORKER_BACKEND=claude_code sends every tool-using turn through ClaudeCodeWorker (one stream-json session in the sandbox root with per-role --allowedTools, then a typed summary on --resume), with the transcript rendered in the shape scio report reads and the usage folded into the ledger and budget by Harness.account. Verify, commits and the gate are unchanged. scio/loop/backends.make_worker chooses the backend at every worker call site; SCIO_CLAUDE_CODE_BIN names the binary.
On the claude_code backend every tier cap in budgets.yaml is scaled by SCIO_CLAUDE_CODE_BUDGET_FACTOR (default 4.0, the measured ratio of Claude Code's estimate to the API price, I-069); the binary's own budget stop is SCIO's graceful budget exit; a claude -p run that fails without a message is retried (I-068); over-long prose fields in a typed summary are trimmed rather than failing the turn (I-070). scripts/nightly_live.py --provider claude_code runs the nightly suites on the subscription, one trial at a time.
scio build --product DIR [--gh owner/name] [--decision "<text>"] and scio status --product DIR (Product Mode M8, ADR 0011): the milestone loop. The orchestrator takes the first open feature of PRODUCT.md; an Opus milestone_planner groups up to four into a milestone with a tier each (normalised to a consecutive prefix); a GitHub milestone and one issue per feature are created idempotently by title (offline: files under .scio/product/issues/); each feature runs through the task graph as a subgraph on its own checkpoint thread (build-<product>-<pk>-a<attempt>) on branch milestone/<n> with the tier pinned and its own budget; the profile's full suite and lint run on the branch; an Opus milestone_gate verdict that any failing check overrides; one milestone PR (cost, escalations, plan versus done, Closes #n) stops for the human merge; progress.json and NOTES.md are updated on main and the loop continues. A crash between features or after the PR resumes with no duplicated issue, commit or PR; a feature that halts stops for one decision (retry, skip, stop). merge and stop records the merged milestone and ends the thread; build threads are named per starting milestone (build-<product>-m<n>) and scio build starts a fresh one once the previous ended. New state ProductBuildState, FeatureRun, MilestonePlan; GitHubClient.ensure_milestone, ensure_issue, find_issue, pr_merged; Harness.child; scio report renders a product view for build-* threads; the product graphs are registered diagrams in ARCHITECTURE.md.
Changed
After scio new every feature in progress.json is todo, the walking skeleton included: the scaffold proves the toolchain and P1 is verified by its own feature run (ADR 0011 decision 1, the M7 open question).
Fixed
The local sandbox no longer sets RLIMIT_AS on POSIX: it capped virtual address space, which V8 reserves by the tens of gigabytes, and Node's TypeScript stripper died with "Cannot allocate Wasm memory" on CI (I-084); the CPU-time and wall-clock limits stay, and Limits.memory_mb is enforced by Docker.
On the Claude Code backend a --json-schema answer is a StructuredOutput tool call that Claude Code bounces with a schema error when it misses the schema; with --max-turns 1 the model had no turn to retry and the first live http milestone crashed error_max_turns in the explorer's summary (I-077). Schema calls (worker summary, provider structured) get three turns and a capped summary is re-asked once with the required keys named.
scio new --thread X --decision ... without --dir continued in a default directory instead of the one the thread was started in, so the first live http bootstrap landed under .scio/products/ (I-076); the resume now reads the recorded directory from the checkpoint and reports an ignored --dir.
The product environment exposed the base interpreter's packages (--system-site-packages), so CI's runner had no pytest inside it and every Fake product build stalled there while the dev machine passed (I-074); see Added. Windows Application Control blocks the venv's pytest.exe and scio.exe launchers on the dev machine: python -m scio exists now and CLAUDE.md uses the module forms (I-075).
scio new ran the interviewer and the product planner twice and approved a draft the human never saw: a node re-runs from its start on resume, and both nodes made their model call and interrupted in the same node (I-065, found by the first live run after M8). The stops are now their own nodes (answers, approval) reading the draft from state; a Fake test with a planner whose draft changes every call guards it.
Verify's "something changed since the base commit" check read git diff --stat, which ignores untracked files, so a feature delivered only by new files stalled as "no changes" (I-063); diff_stat lists untracked files and the full diff stages them with git add -N.
uv.lock recorded the project at 0.3.0 after two releases (I-062); relocked, and test_version.py now checks the lock.