Skip to content

Releases: phased-execution-public/phase-console

v9.0.0

Choose a tag to compare

@zsarir zsarir released this 29 Oct 00:12

The session made cheaper, measured. 9.0 is the work of plan measured-console: the skill is a
core and three mode files, a supervised session is told what it starts from at its start, the gate
runs every suite once and a phase verifies what it changed, the plugin is the skill alone, and a
phase session boots on 55K tokens where 8.0's booted on 111K. The free tree stays MIT. PE_API is
3: nothing an 8.x plan, session or script says changes meaning, except where Migration says so.

Migration

Every entry names the file that owns what it changes. Nothing an 8.x plan says changes meaning: each new
plan line below is optional, read by both engines, and silent where a plan says nothing.

  • The skill is a core and three mode files (PE_API 3, PE_API_MIN 2). SKILL.md is the console
    contract, the modes as pointers and the guardrails (under 16 KB); Mode 1–3 are
    references/mode-plan.md, references/mode-phase-start.md and references/mode-phase-finish.md,
    each read whole in its mode; the helper catalogue is references/scripts.md, and the engine prints
    its own (phase-graph.sh --help, --explain, --section); the maintainers' scripts are
    docs/maintainers.md. A console at PE_API 3 still runs a skill at 2, and a console at 2 runs this
    skill, so the 8.0 plugin and an updated console work together either way round. A flag added to a
    session-facing script is now a stamp bump, held by viewer/test/skill-api-ratchet.test.ts. Owner:
    scripts/skill-api.env.
  • The plugin is a materialized tree, and it carries its own hooks. The skill installs as a
    skill-only tree of about 2.0 MB, and assets/console.gif is gone (the READMEs link the v8.0.0 tag's
    copy). hooks/hooks.json carries the four presence events, so install-hooks writes nothing over a
    config dir whose installed plugin already has them; phase-console install-hooks --splice keeps
    splicing them into settings.json, and while a spliced entry exists the plugin's copy stays silent
    (PE_PLUGIN_HOOKS=1 overrides). phase-console update-plugin installs the tree (--tree).
    Owners: scripts/build-plugin-tree.mjs, hooks/hooks.json, viewer/server/hooks-install.ts.
  • autopilotLoads defaults to console-set: an unattended session loads the console's own skill
    tree and the plugins in autopilotPlugins (default none, name@marketplace only), under
    --setting-sources project,local — the operator's user-level plugins, hooks and settings no longer
    load; their deny rules still do. Set autopilotLoads: operator-config to keep 8.0's behaviour.
    Owner: viewer/shared/prefs-model.js (resolved by viewer/server/runner/loads.ts).
  • The run's hooks block on failure (onFailure: "block" on every hook the console registers): a
    hook that errors refuses the call instead of letting it through. The Stop hook's refusal now takes
    effect, so a session ending on red fast lines is held once; - **Fast gate:** off on a phase turns
    that off. Owner: viewer/server/runner/approvals.ts (HOOK_ON_FAILURE).
  • The gate's marker is a record in the common gitdir. It was a bare sha at git rev-parse --git-path phase-console-gates-ok; it is now phase-console-gates-ok and
    phase-console-gates-ok.json under git rev-parse --git-common-dir, so a linked worktree counts for
    the repository. Only a green full-matrix gates.sh run on an unmoved, clean HEAD writes it (a dirty
    tree exits 2; a phase-tier run writes nothing), and the pre-push hook and the release's
    --gates-passed check refuse a bare sha or a record whose stages do not cover gates.sh --list. A
    .build-rev that is not HEAD fails both tarball gates. Owner: scripts/gates-marker.sh (written by
    scripts/gates.sh).
  • New optional plan lines: **Subagent model:**, - **Fast gate:** and - **May delete tests:**
    (measured-console phase 6), - **Skills:** (11), **Verification tier:** (15), **Evaluator:**
    (22), **Canary:** (24), **Plugins:** / - **Plugins:** (27), - **Out of scope:**, ## Not yet specified and - **Amendment:** (30) — each with a fixture, and each printed by its
    phase-graph.sh mode. Owner: references/plan-format.md (read by scripts/phase-graph.sh and
    viewer/server/parse/plan.ts).
  • The session model is re-fit: 55K + 183K + 1.91 × weight, where it was 121K + 198K + 2.17
    (reports/p33-after.json), so --session-plan batches more weight into a session than it did under
    8.0. Owner: scripts/sizing.env.
  • humanStepMode defaults to defer on a CLI at 2.1.306 or later (and park below it): a run
    that says nothing now pauses a person's step at its call instead of ending the turn. Set
    humanStepMode: park on a run to keep 8.0's behaviour, which is byte-identical in the journal.
    Owner: viewer/shared/run-settings.js.
  • compaction defaults to console: nothing changes until a run chooses native or alternate.
    Owner: viewer/shared/run-settings.js.
  • The presence hook's SessionStart entry waits 15 seconds (the brief). An install from before
    reads brief: false in hooks-status — presence still works and the boot prompt stays whole — until
    phase-console install-hooks refreshes the entry in place. Owner: viewer/server/hooks-install.ts.
  • A run's journal is a chain at its cap (measured-console phase 17): at 32 MB run-<id>.jsonl is
    renamed run-<id>.jsonl.<n> (n from 1) and indexed in run-<id>.jsonl.index — {n, file, firstSeq, lastSeq, bytes, offset} per segment — and the fresh file opens with journal.rotated. seq runs on
    unbroken and every reader follows the chain; a tool that parsed run-<id>.jsonl alone should read
    the index's segments first. journal.full applies only past eight segments. Owner:
    viewer/server/runner/journal.ts.
  • A run's record persists incrementally (persistModel 2): run-<id>.json is the base, and a save
    appends the records it changed to run-<id>.json.delta — one fsync — rewriting the whole file at
    most every minute, on a status change, or past a 4 MB delta. The first 9.0 boot rewrites every stored
    run once into the new shape and journals run.persist-v2 on it. A tool that parsed run-<id>.json
    by hand sees every status change at once and other fields within a minute; fold the delta's lines
    past the base's persistGen for the rest. Owner: viewer/server/runner/state.ts.
  • Runs that never finished age out: a halted, parked, paused or interrupted run untouched for
    runRetainDays (30) is pruned with its files, as a finished one always was. Owner:
    viewer/server/retention.ts.
  • Webhooks are signed and queued: every POST carries X-Phase-Console-Signature: sha256=<hmac>
    over its body with the destination's secret (shown once at add; older rows get one at first boot),
    and a destination in backoff holds every announcement and delivers them in order when it is back.
    Owner: viewer/server/webhooks.ts.
  • validate.sh's size warning is about the handoff's body now, not its start section: a long
    generated section over a short body says nothing. Owner: scripts/validate.sh.
  • Words settled where they live: nineteen decision keys everywhere (issues included); an
    unsupervised declaration lands as outcomes/phase-NN-<stamp>.json; a lock's branch AND tree carve
    two intersecting scopes apart; **Wait budget:** is the total one phase may spend parked; the
    default target model is claude-opus-5-5; Haiku is for subagents (a 200K window cannot hold a phase
    session's floor); BUDGET_BIG's note says it is a preset, not a measurement; a session commits after
    each green step and leaves pushed history alone; the plugin listing's description is a paragraph,
    not a changelog. Owners: references/plan-format.md (the keys and the plan lines),
    scripts/models.env (the model ids) and scripts/sizing.env (BUDGET_BIG).

Added

  • A person's step pauses the session at its call and resumes it in place. Under the run setting
    humanStepMode: defer the hook defers the phase-outcome.sh … needs-human call itself, the console
    raises the item from the call, and when the person's check passes the SAME session carries on from
    that call: the script prints the answer (--resumed-with) and declares nothing. park keeps 8.0's
    park-and-resume. phase.deferred, phase.deferred-resumed.
  • A session's outcome arrives typed. Every session that can declare runs under --json-schema
    (viewer/shared/outcome-schema.js, which owns the file's shape too); its structured_output is read
    before the outcome file, and a file naming a different word journals phase.outcome-disagreed. The
    script keeps writing the file, so a hand session declares exactly as before.
  • Native compaction is an arm. compaction: console | native | alternate and compactionWindow
    (350,000): under native the session gets CLAUDE_CODE_AUTO_COMPACT_WINDOW, the console's
    PreCompact/PostCompact hooks journal phase.compaction (before, after, the re-cache), the 0.8×
    checkpoint is off and the 0.6× line is a notice; alternate gives odd phases native. A resumed
    session's own SessionStart cost is kept (phase.resume-cost) and quoted by the next resume brief.
  • A wrap-up pushes what is green. The 0.6× notice says commit AND push where the plan's
    permission.destructive row allows git push origin <branch>; phase-outcome.sh partial warns of
    every scope tree ahead of origin/<branch>; a checkpointed session's fast-forward is pushed by the
    console (to the origin it had before the session, under the hardened git); and the phase shows its
    unpushed commits — the inspector's Unpushed and a heads-up on Your turn — until a push lands (#397).
  • A supervised session is told what it starts from at its start, not in its prompt. The presence
    hook prints the phase's brief at SessionStart — phase-graph.sh <slug> --brief N: the mode f...
Read more

v8.0.0

Choose a tag to compare

@zsarir zsarir released this 19 Oct 18:52

Every open issue, fixed. 8.0 fixes every issue that was open on 2026-10-17: Your turn becomes a
page you work from and the eighth destination, the phase graphs become instruments, any MCP server
signs in on the page, the runner's mirrors, lanes, landing, watches and gates stop losing work, the
load guard reads the machine's real CPU, and the console's own git is hardened. The free tree stays
MIT. PE_API stays 2: nothing a 7.1 plan, session or script says changes meaning, except where
Migration says so.

Migration

  • The accounts registry is v2 in both editions. A v1 accounts.json is upgraded in place on its
    first read and copied once to accounts.json.v1.bak.
  • A push is read by its clause. A bare git push is now deny. A trunk (main, master,
    trunk, the run's base) is pushed only where a permission.destructive row names it with its
    phases (`main` by phase 34); a negated phase list (never, not, no, except, !)
    excludes those phases, and a clause with only negated phases grants nothing. A forced or deleting
    push, --no-verify or another remote asks a person even under a whole Bash(git push:*) rule.
  • The console's own git ignores the system config (GIT_CONFIG_NOSYSTEM=1) and runs no hooks
    (core.hooksPath=/dev/null). A credential helper set only in the system config (macOS
    osxkeychain) is no longer seen: set credential.helper in ~/.gitconfig.
  • A plan's **Branch:** line names a branch only in backticks (`pe/<slug>`); bare prose
    names none. A repeated ### Phase N section fails the lint (F21 phase-section-repeated), and the
    JS parser joins it under the first.
  • decisions.sh refuses a --value over 500 characters, an --evidence over 200 and a --by
    over 64 (exit 2) instead of cutting them.
  • The landing ledger moves forward only: phase-landing.sh keeps a row that is further along and
    says so on stderr, unless --allow-backward.
  • close-plan.sh --status complete refuses while the plan's work is unlanded, open or unfiled,
    naming each item; --force closes it anyway and records how many were open.
  • A press from a page of an older release is refused with a 409 and a sentence asking for a
    reload (x-build-rev). The CLI, the scripts and the hooks send no such header and are never
    refused.
  • The load guard's loadGuardFactor keeps its name and changes its meaning: it now scales a CPU
    reading (85 % busy over 30 s at factor 1.5), and the 5-minute load average is only a ceiling at
    factor × cores × 2.
  • Your turn is the eighth destination. The phone's tab bar reads Runs · Your turn · Plans ·
    Sessions · More; 7.1's ?view=compact on Your turn reads as the list.
  • phase-outcome.sh verified writes repo and repo_tree, so a proof is keyed to its own
    repository.
  • New state: mcp/registry.json under the instance's state directory (the MCP registry's
    24-hour cache).

Added

  • Your turn is a page you work from (#377, #366, #365, #334): the eighth destination and every
    plan's fourth view (#/turn, #/plan/<slug>/turn), with tabs (Open · Done · Handled by the AI ·
    All), four views (list, board, cards, timeline), five groupings and three sorts in the address; every
    status word explains itself on hover, focus and tap; the bell's drawer is a five-row preview with
    Put back (POST /api/notifications/unread).
  • The phase graphs are instruments (#376, #364): the map's filter chips, trace, colour, layers,
    layouts, hover card and SVG or PNG export, each in its address; two new readings, Schedule and
    Burn-up; the timeline's zoom and quick ranges; and a lock map on Sessions ▸ Locks.
  • Tables and cards that say more (#361, #360, #369, #362, #305): an outlined status badge, a plan
    track drawn to proportion with its legend, Sessions rows with what each runs on, its account, model,
    spend and context, a summary strip, the 6.x palette back as Settings ▸ Appearance ▸ Palette
    (quiet or departures), and the halt card on the Runs home.
  • Any MCP server, signed in on the page (#363, #372): the open catalog searched here and cached,
    Add by hand for any server, Fill it in for a ${VAR}, and Sign in told step by step;
    phase-console mcp list | add --manual | fill.
  • Waive this line (#267): an operator waives one red verification line for one phase
    (POST /api/run/<slug>/verify-waive), listed under Waived by the operator.
  • Verification lines read Timed out and Skipped as well as green and red (#331).
  • Two proof lints, both advisories: F45 proof-unparsable (a Human step: proof the check
    cannot read) and F46 proof-script-run-branch-only (a cmd: proof whose script is not on its
    repository's trunk).
  • Two halts that name the tree: run-tree-config (a session changed its tree's git
    configuration) and run-tree-locked (a git lock file nothing is writing blocks the tree).
  • The doctor says more (#343, #279): a deliberately disabled launchd unit is told from a broken one
    with the line that enables it, and a check it cannot see is said, not passed.

Changed

  • The console's own git is hardened (#272), and a push is read by its clause (#276, #275) — see
    Migration.
  • The load guard reads the machine's real CPU (#243, #223): busy over 30 seconds, every console's
    work and in-turn bursts counted. A heavy verification line waits for a seat in one machine-wide
    budget, journalled phase.verify-queued (#327), and a session's orphaned test runners are reaped at
    its end (#222).
  • close-plan.sh closes complete only once the work has landed (#320).
  • A handoff's ▶ Start next phase(s) section is a pointer to next-phase-prompt.sh, composed when
    read (#338); new-handoff.sh --force rewrites the INDEX row it supersedes (#265); a note keeps its
    indented sub-bullets (#378); and every watch scheme is documented (#233).
  • Switching a run's account is a run act, under --allow-run alone (#323).
  • Every CLI verb reaches the CLI (#359), and a release packs the client it names (#358).
  • The boot prompt's wait procedure names the pgrep -f trap (#260): a wait on text in its own
    command never ends; wait on the job's pid or a file it writes.

Fixed

  • Your turn's presses and proofs (#368, #367, #371, #351, #374, #345, #350): Send my decision
    sends once and then checks the proof; an item bound to a gate closes when the gate opens; a reminder
    keeps a returned item on Redo; a proof whose script is missing reads Cannot run instead of
    failing you; and one reader reads every cmd: proof.
  • Your turn's inputs (#346, #349, #393): a Human step: inside an HTML comment is ignored,
    --needs issues is classified as itself, and the page's touch targets are full size.
  • The graphs draw no text over text (#375, #299, #342, #306): below 9 px only numbers show, marks
    that share a spot read ✎×4 or ●+3, the track sits behind its labels, a Runs row keeps its count
    on one line, and the run clock counts frozen time once.
  • Small things on screen (#339, #335, #315): a chart's heading is named, short code tokens do not
    break, and a dropdown fits the screen.
  • An update never paints the old release (#373), this browser is found by its push endpoint
    (#325), a placeholder delivery counts as no device and no failure (#314, #324), and a repaired push
    clears its health row (#280).
  • Mirrors and verification (#356, #357, #311, #301, #328, #333, #262, #283): a run's mirror grows
    when its plan adds a repository, a docs-only line runs where the docs are, Verify in: . means the
    plan's tree, a proof is keyed to its repository, an orphaned index.lock is named, a resolved run's
    trees are swept, the artefacts register credits only a phase's own trees, and an unexpanded $VAR
    is never taken for a path.
  • Lanes and landing (#354, #295, #370, #336, #249, #240): a phase keeps its lane while it holds
    work in the shared tree (run.lane-held), the landing proof fetches and recognises a squash or
    pull-request merge, and the landing ledger never moves backward.
  • The lint and the decisions (#225, #228, #226, #235, #322, #253): a sibling's half-written
    handoff no longer fails your lint, a repeated phase section does, a person's resume re-reads the
    decisions, the Branch line is read right and a shared launch asks about it, and an over-long
    decision is refused rather than cut.
  • Watches and gates (#337, #303, #245, #264, #239, #288): a watch beside a long cmd: row is
    asked, Resume re-asks a settled wait, Recheck works on a waiting ref, a live run re-reads its held
    gates, and a phase whose dependency is not done is held, never boarded (phase.dependency-held).
  • Detectors and in-turn waits (#219, #220, #259, #260, #292, #274): a phase serial behind a live
    lane is not undriven, the watchdog holds while a tool card stands, a turn ends without a ten-minute
    idle wait, a wait loop whose pgrep -f matches itself is refused, a wait on a detached job's file
    arms its own cmd: ref, and a git ref after "held by" is not read as a lock.
  • The inbox answers without lag (#237).
  • Accounts (#238, #287, #281): a run's start goes to the first account with room, the usage brake
    keys to the account a session really spends, and a pinned model is checked on every frame, so a
    fallback mid-session parks the phase.
  • The tests are hermetic and say why they fail (#353, #352, #344, #294, #291, #297, #329, #326,
    #316, #394, #289, #302, #313, #241, #318, #246, #256, #230): tests/run-tests.sh scrubs every
    PE_* and DOCS_ROOT before bats, a test process's usage poller reads no meters unless given one,
    and a test file that stops mid-run fails the gate.

v7.1.0

Choose a tag to compare

@zsarir zsarir released this 14 Oct 01:36

Your turn, told step by step. 7.1 makes every item on Your turn a card a person can act on without
reading anything else: one of four types — an Approval, a Task, a Decision or a Heads-up — with
numbered steps, NOW or NOT YET and when, a timing grid, where a press goes and who checks it, and one
act form for its type. Every word on the card comes from one composer, so the bell, the Runs home, the
lock screen and the page say the same thing. What only the run can do, what went stale and what the
AI could do itself no longer reaches a person as a chore. The free tree stays MIT. Nothing a 7.0
plan, session or script says changes, and PE_API stays 2: an item a 7.0 console raised keeps its id
and state and gains the new words when it is read.

Migration

  • The page's groups are v2 (TURN_GROUPS): Approve · Do now · Decide · Being checked ·
    Coming up · Done, placed by the item's type and readiness, with Handled by the AI, Heads-up and
    Where the plans stand as sections. 7.0's Needs one detail from you is gone: such an item is a Task
    on Redo in Do now.
  • GET /api/turn gains the card contract on every item — type, personStatus, readiness,
    route, checkedBy, timing, steps, verdict and verdicts, and options or approval where they
    apply — plus strip and headsUp on the answer. Every field 7.0 sent is still there.
  • A plan's Human step: bullet takes three more keys, options:, recommended: and deadline:,
    validated by both parsers and printed by neither, so phase-graph.sh --human-steps is byte-identical;
    its guide: key is now read as a file under the docs root (F42 guide-file-missing gates).
  • New routes: POST /api/human-steps/:id/undo and POST /api/run/:slug/run-request (an authority
    route). A run verb pressed from a card carries expectRunId and answers 409 with a sentence when the
    plan's run is another one.
  • New state files under the instance's state directory: turn-first-seen.json (when a projected
    item was first seen) and turn-settled.json (how a pressed projected item ended).

Added

  • The card (client/src/cards/turn/): NOW or NOT YET with its when, the type's mark, the
    person's status (To do, Checking, Passed, Redo, Not doing, Closed, Waiting for the
    owner
    ), the title that names the act and its meta, a timing grid on one page clock (Assigned, Do
    it
    , Deadline, Open until, You sent it, Checked), why only you, once, the verdict before the
    steps, From the AI, the numbered steps, How it's checked, Goes to and Checked by, and one act
    form per type, its primary chosen by one move table. Every command a person runs is one command
    block, and a command with a <placeholder> is a template to fill in.
  • The page: a strip (to do, checking, passed today, the next deadline) under the headline; one
    toolbar row whose Filter (Status, Time, Plan, Type, Goes to), Group, Sort and View live in the
    address; Heads-up; and Where the plans stand, one line per plan. #/turn/<id> marks its card and
    opens the panel on it where the panel stands beside the page.
  • One composer (server/turn/compose.ts) writes every word of every item and of its inbox row
    and push. Steps come from the authored guide, else the plan's errands row, else the situation's own
    words, else a minimal guide from the link or command and the check said in words
    (shared/proof-words.js); no proof ref, route or "phase 0" reaches a person.
  • Plan-born guides: a Human step: bullet's guide: file is read, and a plan's ## Operator errands table is read by its headers; a bullet ending in (E-N) takes that row's steps, and a row
    no bullet names is a Heads-up. New advisories F41 human-step-no-guide and F43
    errand-row-unbound, and the gate F42 guide-file-missing.
  • What each situation asks: every ask the console raises carries a title, steps, a check and
    options bound to their verbs; a gate, a plan approval, a permission and an owner request carry an
    approval block (what, who asked, if approved, if denied); an identity park offers exactly its two
    choices.
  • Where a press goes: Undo: I'm not finished takes back a running check; a press that ends an
    item waits a few seconds on the page with Undo; Hand it back gives an item back to its phase
    (Give back to Phase N), asks its session a question, or says you cannot; a pressed approval card, gate,
    plan approval or question leaves a record, so Done shows how it ended, by whom and when.
  • Run requests: phase-outcome.sh … blocked --needs run --run-act <act> asks the run to relaunch
    isolated, switch account, raise a phase's budget, stop or hold — one Approval per run and act, every
    asking phase a waiter; Approve takes the act and resumes them, Deny tells them no.
  • Items that close themselves: a stopped run a later run of its plan supersedes is resolved by
    itself (journal run.superseded, undone by unresolve), and the round closes its run-specific items,
    those of a phase the board reads done and those whose errand is gone — each with a row under
    Handled by the AI — while a sign-in, a secret or an errand at the machine moves to the new run.
  • Every surface in the card's words: the Runs home's and the bell's rows lead with NOW or NOT
    YET and the type, and a push's lock screen is chosen by type — a Task Open and I did it, a run
    request Approve and Deny on a console with --allow-run.
  • The help guide's Your turn, in English and Persian, explains the four types, the statuses,
    NOW and NOT YET, the timing grid, Goes to and Checked by, Undo, Hand it back and run
    requests; the README, USAGE, viewer/README.md and references/turn.md say the same.
  • Tests: every card the console can raise is walked in both editions and held whole
    (viewer/test/turn-cards-coverage.test.ts), and the tower rehearsal drives a card's round trips on
    real consoles.

Changed

  • A permission is approved at a scope — Approve, this call to Approve, always — and sits in
    Approve, where Grant every low-risk ask now stands.
  • A decision's button is Send my decision, and nothing is chosen for you.
  • The identity park skips a superseded run and never overwrites an operator's stop.
  • An operator's act is an act of its phase: two phases asking for one command are two items,
    each on its own clock (#261, #257).

Fixed

  • human-step-model.test.ts expects the births there are (#271).
  • An inbox row no longer reads a human step's window as a question's countdown (#341).
  • An act due at a date ahead reads Coming up, not notified at once (#255).
  • An answer pressed while its run is still parking reaches the run (#273), and an in-process
    resume through an automatic door no longer takes the person's slot
    (#268).
  • Your turn's panel says a person's reason once (#332).
  • A section heading's count keeps its gap right to left (#296).
  • A run request a live run declares raises its item before the run reaches disk, an answer that
    arrives first raises the item and answers it, a hold released on a parked run resumes the phase that
    waited, and a Done run request keeps its approval block.

v7.0.0

Choose a tag to compare

@zsarir zsarir released this 12 Oct 12:29

Quiet. 7.0 rebuilds the console's web client from zero around one question — does anything need
me?
— answered in two seconds and fixed in one move, with everything else one expansion away. Seven
places (Runs · Plans · Sessions · Repo · Insights · Logs · Settings) under one shell; one line per
thing, a status drawn as a dot and a word, and three doors to depth on every page — expand in
place, inspect in the panel, and Everything, a per-page switch that shows every column, fact
and section. Every option the server has now has a door a person can reach: a registry names each
route, event, setting and operator verb with the page that offers it, and a test holds it to the
server both ways. The whole client works on a phone and a tablet, mirrored right to left, and stilled
for anyone who asks for less motion. The free tree stays MIT. The server, the runner,
the scripts and the skill are the same as 6.2's: nothing a 6.2 plan, session or script says changes,
and PE_API stays 2.

Migration

  • Every 6.2 address still lands, in one hop, with its query (client/src/shell/redirects.ts):
    #/now… and #/ready on the Runs home, #/queue on its Queued group, #/approve on Your turn,
    #/debug[/<section>] on Logs, a 6.2 Runs bay (?bay=) on its group (?group=). A bookmark, a push
    and a link a session wrote keep working.
  • Debug is Logs. The place is #/logs/<section> — Logs, Journal, Delivery, Health, Access — and
    its chunk is logs-*.
  • The run page folds into its plan. A run is a plan's Run view, #/plan/<slug>/run, with its
    earlier runs at ?view=history; the Tower's six bays are the Runs home's groups.
  • New read routes, no flag and no journal line: GET /api/prefs/schema (every preference with its
    type, default, section, description and where its value came from), GET /api/ceiling,
    GET /api/credentials and POST /api/credentials/probe, GET /api/doctor/strays,
    GET /api/sizing, GET /api/report, GET /api/run/:slug/proofs and
    GET /api/run/:slug/verifications.
  • A preference can be reset. Settings ▸ Everything resets a key to its default, and a write keeps
    only what the file held, what the write set and what differs from the default — so a reset leaves
    the file rather than pinning the default in it.
  • First paint is held at 170 KB served (it was 190), in this build and the free one: the free
    tree's gate now runs check:dist on its own client build.
  • The 6.x client is gone. viewer/client/src/ holds ui/, cards/, shell/, screens/ and
    data/ beside lib/, styles/ and content/; the 6.x app, features, components and lib/api
    directories and lib/queries.ts no longer exist. A patch or a fork against a 6.x client file has
    nothing to apply to.

Added

  • The map: seven places in three bands (DESTINATIONS in shared/route-meta.js), the same in
    both editions. The rail from 900 px carries the instance switcher, the seven places, Help and the
    account meter; the header the page title, the situation words, search (⌘K) and the bell; below
    900 px a tab bar — Runs · Plans · Sessions · Insights · More.
  • Three doors on every page. Expand opens a row where it stands and remembers it. Inspect puts a
    record in the panel — a column at 1200 px and up that stays open across pages, a sheet from 900 to
    1200, a bottom sheet on a phone — on four tabs, Overview · Actions · History · Raw. Everything is a
    per-page switch at the end of the toolbar. Every list's toolbar is one row in one order: search ·
    Filter · Group · Sort · View · ⋯ · Everything, and one View sheet on a phone.
  • The Runs home (#/runs): the situation sentence as its heading, then Your turn, Running,
    Waiting, Queued, Ready to start and Settled today, one line per run with exactly one action — a
    halted run's comes from its halt first (#278) — and All runs as a table view.
  • Your turn (#/turn) on the 7.0 cards: the headline and the round, six sections, every item's
    explanation in the panel (GET /api/turn/:id) and Withdraw among its moves.
  • Plans and a plan. The library is one line per plan — mark, name, line, sessions left, moved —
    as a list or cards, with closed plans and documents folded. A plan opens on its glance over three
    views: Phases (one table with the spine in its identity cell, and the route map), Run (the run's
    folds: sessions and their consoles, where the time went, why it started and what it cost, what the
    ladder tried, ways forward) and Source.
  • One launch form with a quick view: the departure line and its route, the findings in order, the
    turns it will ask for, presets, and nine rows that open in place at every width.
  • Sessions (#/sessions): every lane, terminal and Claude session on one grid, a session full
    height, and the locks with their holders, narrowed by the server.
  • Repo as six addressed sections — History, Branches, Working trees, Changes, Settles and the
    Issues desk — each record in the panel.
  • Insights: how long is left, what it costs, what a session may spend, this week's measurements,
    velocity and approvals, each question answered by the server's own arithmetic.
  • Logs: the explorer and its live tail, the journal on a Gantt, delivery, health — the doctor, the
    start ceiling and stray consoles — and access, plus the redacted bundle.
  • Settings as one place: an index with what each section holds, a section per address, search that
    answers sections and keys with their controls, and Everything — every key the server describes,
    with its value, default, origin, reset and, for a key only the CLI or the machine sets, the line
    that sets it.
  • The palette's do: every operator verb, each saying when a capability flag disables it; and the
    panel's Actions tab per record kind.
  • The surface registry (client/src/data/surface.ts): every route, server event, settings key
    and operator verb, each with its door or an exemption naming its caller, held both ways by
    viewer/test/surface-parity.test.ts with nothing left unassigned.
  • The help guides describe 7.0, in English and Persian: Runs home, the launch's one screen, and
    Getting around's card per place and its three doors.

Changed

  • Status is a dot and a word (client/src/ui/status/): the eight hues at one weight paint a 6 px
    dot, a track segment or a row's edge, never a chip behind text; settled things wear a hollow dot.
  • One type face at four sizes, one cool neutral room in two lights, rows separated by space, a card
    only around a thing acted on as a unit, and one shadow, for overlays. The design law is
    viewer/docs/design.md; every rule in it names its guard.
  • One stream per browser. A second tab no longer breaks the first (#236): one tab holds the
    console's event stream and shares it with the others, and a session console asks for its run's
    stream only while it is on screen.
  • Lists read projections, the slim run list for the home and the header, the full record only for
    the open run (#234's client half).
  • A long token breaks only where it must. A path, a slug, a label or a command in a cell or a
    sentence wraps at its own spaces first and breaks inside a word only when the word alone is wider
    than its box (wrap-anywhere, where 6.x broke every word at the line's end).
  • Phone, tablet, right to left and reduced motion are proven in a real browser on every
    destination: the three doors by thumb at 360 and 768 px, every stop mirrored under dir="rtl",
    text finding its own direction, and motion stilled when the system asks.

Removed

  • The 6.x client — its app, features, components and lib/api directories, lib/api.ts,
    lib/queries.ts and the two helpers only they used — every shim, every lint exemption and every
    frozen allowance that kept them, and seven dependencies only they used (react-hook-form,
    @hookform/resolvers and five Radix primitives).

Fixed

  • The phone's situation line has its inline padding (#284).
  • The owner's confirm prompt shows the request it confirms — the body it replays, never a
    self-chosen label (#277).
  • An item leaves Your turn only when the server says so, so a grant's Allow no longer dismisses an
    item before the grant is known to have applied (#270).
  • A decision step's options are its primary moves, and a proof re-run reports its exit (#266).
  • Retention's settings save (#317).
  • Settings ▸ Essentials ▸ Keyboard lists the keys the help sheet does: ⌘K, /, ⌘I, Esc and the
    panel edge's arrows (part of #334).
  • Tests red only under the full gate's load — the write menu, the figures, the help sheet, the
    rehearsal and the notifications specs — were rewritten with the screens they drive (#247, #227, #269).
  • Two node suites red since the rebuild began — a stray status reader and a free package file list
    missing a shared module (#293).

v6.2.1

Choose a tag to compare

@zsarir zsarir released this 08 Oct 19:41

The public tree names no paid package. A patch to 6.2.0, with nothing to migrate: two strings in
an end-to-end fixture named the paid package, and 6.2.1 gives the fixture a neutral package name. The
free tree stays MIT. Nothing a 6.2 plan, session or console does changes.

Fixed

  • The tests name no paid package and no paid route (#282). An end-to-end fixture
    (viewer/e2e/fixture/seed.ts) named the paid package in an item's proof and in a permission's
    command; both now name a neutral one, acme-widget. Two server suites, inbox.test.ts and
    console-forge.test.ts, spelled routes only the paid tree serves; the free tree's copies assert each
    action's verb and method instead.

v6.2.0

Choose a tag to compare

@zsarir zsarir released this 08 Oct 11:29

Your turn. 6.2 gives every act only a person can do one page, one shape and one road back to the
work that waits on it. A sign-in, a code, a secret, a payment, a permission the AI lacks, a decision,
an errand at the machine: each is an item on Your turn (#/turn) that says why only a person fits it,
carries a guide to follow and a proof the console checks, so I've done this — check comes back
passed, or sent back with exactly what to redo, and no session can pass its own. A permission ask is
answered by a grant with a scope and an end — this call, this phase, this plan, this repository or
always — that the server applies, audits and can revoke, beside a never list no door lowers. An owner
key, a passkey, lets a console tell its owner's press from any other door's. The console keeps the
page current by itself, and the approval, gate, question and errand cards elsewhere draw the item and
link to it. The free tree stays MIT. Nothing a 6.1 plan says stops working — what moved under people's
feet is below.

Migration

  • Update the console's scripts and the plugin together. PE_API is 2, and a run refuses to start
    when the console's and the skill's stamps do not meet, naming the half to update. A 6.1
    phase-outcome.sh takes none of a person's turn's new flags and never exits 4.
  • A person's turn carries a reason. A needs-human --step declaration says why only a person fits
    it — --why, one of ten reasons, held to what its kind allows — and one that names none is given its
    kind's default, marked inferred, so an older skill copy and --act keep working. A plan's
    - **Human step:** bullet gains why:, effort:, unblocks: and guide:; a bullet with no why:
    draws the advisory F40, never a gate.
  • A step needs a proof. A step with no --proof, no --proof-words and no answer for a result is
    refused (exit 2); name --proof-type attest to take the person's word.
  • Exit 4 is the guard's. phase-outcome.sh exits 4 when a declaration asks a person for what the
    AI could do itself — a permission or reserved reason whose every guide command the run's own
    policy allows, a reach with no --tried — or a permission block cites no wall the console
    recorded (G5). Read 4 as "run it yourself", never as a malformed call; --tried is the answer when
    running it failed.
  • "Done — continue" is I've done this — check. A person errand is an operator-act item, and its
    row's action, like every check button, reads I've done this — check. A check now comes back with a
    verdict — passed, rejected with exactly what to redo, or needs-info — rather than "landed or not",
    and a probe that misses leaves the item returned, where it used to read notified.
  • The secret-entry field is gone. The console never takes a secret: check refuses a body that
    carries one, and the item names where the value goes instead — the keychain item phase-console-<id>
    on macOS, a 0600 file elsewhere, or the item's own credential: place.
  • #/approve redirects. #/approve and #/approve?step=<id> land on Your turn (#/turn,
    #/turn/<id>) in one hop, so a bookmark keeps working; a push opens #/turn/<id>.
  • A grant has a scope and an end. The approval card's Allow with remember, the widen card's Allow
    and a standing card's one-time allow are grants now — call (spent on use), phase (until it
    settles, 24 hours at most), plan, repository (a new policy layer between the plan's file and the
    machine's) or always — each a row in grants.ndjson saying exactly what it changed, and a revoke
    undoes exactly that. The widen card no longer strikes a rule from the plan for good. A grant below
    plan scope lowers the rule in that run's settings until it ends, and for that long the CLI's own list
    does not hold the rule with the console dead.
  • What an owner key changes for a script that presses the console. Nothing until a key is enrolled:
    a console with none behaves as before, and /api/state.ownerDoor reads unenrolled. Once one is,
    an authority press from a script, the CLI, a browser with no key, a phone beyond its low and medium
    answers or a session's token is answered 202 {requested: true} — recorded on its item as "asked by
    — confirm?" and pressed only when the owner confirms — so a script reads 202 as waiting for
    the owner, never as done. What the plan's manifest already allows still executes through any door.
    by in a body is only a label: the door a request proves is recorded as pressDoor, and a request
    carrying a session's token presses no authority route its plan's permission.destructive row does
    not name (403, owner.door-refused).
  • A turn's push names its buttons by kind: Open and I did it for an act, Allow and Deny for
    a low or medium permission at its narrowest scope, Open and Deny for a high or never one, Open
    for a decision. Quiet hours are one setting, the device's: at the first boot a console-wide
    reminderQuiet window moves onto every subscribed device that has none of its own, and is dropped.
  • For readers of the vocabularies: a person's turn has an eighteenth kind, permission, and eleven
    states with returned and declined; viewer/shared/turn-model.js (twin scripts/turn.env),
    viewer/shared/guide-grammar.js and viewer/shared/door-model.js are new owners; the push catalogue
    has a twentieth category, granted.
  • git send-pack and git http-push are walled like git push (control-tower phase 141): two
    default deny rules, the same on every profile. A plan that publishes through either names the rule in
    its permission.destructive row, as it names git push.
  • A guide line may not hold an invisible or direction-changing character (control-tower phase 141):
    a control character, a zero-width space, a bidi embedding, override or isolate, a word joiner or a
    byte-order mark refuses the guide at that line, and a link holding one is not openable. The joiners
    and the direction marks (U+200C–U+200F) stay, so a Persian guide reads as before.

Added

  • The docs say what 6.2 adds, in English and Persian (control-tower phase 140). The help sheet's
    Your turn guide is rewritten around the page — its six sections, why only you, the guide, the check
    and its verdicts, your other moves, the phone — and Permissions says what a grant is (its five
    scopes, its risk tiers, its end, the ledger and the revoke), names the never list and the three
    publishing asks auto-grant never answers (git push, gh pr create, gh pr merge; it said two),
    and gives the owner key a section that ends with what the key is not: a process running as you that
    deliberately rewrites the console's own files can forge anything below the owner key, and can replace
    the key registry itself; the console walls the paths a session takes and makes every grant visible,
    and it is not a boundary against your own account.
    The tower, mobile, notifications and reference
    guides, README, USAGE and the console's README follow, each with its Persian twin, section for
    section. For sessions, references/turn.md is new — the reasons with an example each, the guide's
    grammar and the plan's **Guide language:** line, a template per kind, the proof types, the guard's
    seven rules and how to answer each, a permission block, the answer's road back, handled and the
    doors — and SKILL.md's rule names the five things a session does: give the reason, write the guide
    in the plan's language, state the proof in words, never ask for what it can do itself, and record
    what it handled; a denied tool is declared, never routed around, and the console is never pressed.
    skill-sync.test.ts and guide-coverage.test.ts hold each against the code it describes.
  • A decision names its ## Decisions row (control-tower phase 140, the deferral phase 133 left).
    phase-outcome.sh … needs-human --step decision takes --decision-key KEY: the person's answer is
    written to the plan's decisions table through decisions.sh before the session is resumed with it.
    Any other kind, or a key outside the manifest, is refused (exit 2).
  • The old cards move in (control-tower phase 139, closes #216). Nothing draws a person's ask in a
    shape of its own any more: the approval queue, its question card, the gate card and the errand card
    each draw the ITEM — one row, the kind's mark, the title, ONE primary pressed exactly as the server
    spelled it, and Open on Your turn (#/turn/<id>), where everything else is one press away. A
    low or medium permission's row grants in one press; a high or never one, or a choice of options,
    opens the page. A gate no run is asked about keeps the plan's own Approve (gate-status.md). The
    Needs-you bay keeps runs: each strip's one action is its oldest item's primary, the loose rows and
    Coming up moved to the page, and one line links there with its counts; Your turn (n) in the
    situation line counts items (an errand and its step are one) and opens the page. The launch door lists the run's items — the
    pre-cleared shown done, Do it now opening an item a launch before this one raised — and a plan
    step marked auto-open: host now OPENS at launch, on the machine, behind --allow-terminal or
    --allow-agent, an http/https link only, once the door has shown it whole (the launch sends
    back exactly the links it showed); a session's step never does. A physical item with a link
    shows it for the phone. Not doing this is a person's no; the dead Dismiss fetcher
    is gone. A broker card's
    Allow that a keyed console turns into an owner request is toasted "asked of the owner", never "done".
  • Grants and owner keys on the screen (control-tower phase 138, closes #215). A permission item on
    Your turn is answered in one press on its own card: "Raised because the AI lacks permission to …",
    the command, why the phase ne...
Read more

v6.1.0

Choose a tag to compare

@zsarir zsarir released this 06 Oct 14:21

The world outside a run. 6.1 lets an unattended run wait on what happens outside its own checkout,
and tells the truth about where its work stands. A wait can watch a job on another machine
(unit:<host>/<unit>), a date can stand beside a live ref as its backstop, a plan can raise its own
wait count, and the operator's own acts — a command to run, a click path to follow — form one queue
whose entries come due when their trigger lands. A run is settled only once its branch has landed on
the trunk, a manual gate is a person's alone, a session can no longer press its own console, and the
Issues desk reads a repository's whole issue list, each issue with its category, severity and plan
status. The free tree stays MIT. Nothing a 6.0 plan says stops working — what moved under people's
feet is below.

Migration

  • A manual gate is a person's. A gate the plan marks manual is never delegated to a session,
    whatever the gates row says. gate-status.md gains a Door column, and --gate-status honours a
    manual approval only when a person's door — the console's Gate card or a person's own terminal —
    wrote it, so a row written before 6.1, which names no door, no longer clears its gate: approve it
    again.
  • A run is settled only once it has landed. A run that owns a branch reads finished only when
    every repository's pe/<slug>, the root's included, is held by origin/<trunk>; until then it parks
    unlanded with one merge errand, where 6.0 called it finished. Under landing: hold nothing moves
    the branch onto the trunk by itself.
  • A session cannot press its own console. A supervised session's HTTP client (curl, wget,
    http, xh) against a console's approval, policy, run-settings, gate or person's-step routes, and
    its writes into the console's state or config directories, are denied before they run
    (console-forge). A phase that must press one names that press's CLI form in the plan's
    permission.destructive row.
  • A §Verification line runs without CI=1. The console no longer sets it, so a suite that changed
    its behaviour on CI runs as it does in the session; non-interactivity comes from NO_COLOR,
    TERM=dumb and a closed stdin, and a CI the console itself was started with passes through.
  • A session's turn ends after its own agents. While a background subagent or monitor the session
    launched still runs, the Stop hook refuses a partial or complete exit (twice at most) and names
    the two ways out: wait for it in one bounded foreground call, or stop it and record what it was doing.
  • A new advisory lint, F39 setup-deps-missing, names a §Verification line that runs a package
    script or a .venv/bin/* binary in a repository the phase's - **Setup:** installs nothing for.
    Add the install to Setup; the lint never changes the exit code.
  • Update the console's scripts and the plugin together, as at 6.0: a 6.0.0 phase-outcome.sh has
    no --act or --due-when and knows no unit: ref, and a 6.0.0 phase-graph.sh has no
    --wait-count or --verify-in arm.
  • For readers of the vocabularies: a person's turn has a seventeenth kind, operator-act, and a
    ninth state, upcoming, first in the path; a run has a new halt kind, unlanded.

Added

  • A wait on another machine's job (control-tower phase 121, #181). A new watch scheme,
    unit:<host>/<unit>, asks a systemd unit on another machine whether it is still running — over ONE
    shared ssh connection per host (ControlMaster, its socket under the console's state directory),
    every 5 minutes — and lands the moment the unit leaves activating/active, recording its Result=
    and exit time in the wait history. The host's address, user, key and port come from hosts.<name> in
    the machine profile ~/.config/phase-console/fleet.json; a host not named there is refused, and none
    of those details is written into a run record — ssh's own failure is told in fixed words of its class,
    never its text. The master socket lives with the instance's state, or, where that path would overrun a
    Unix socket's 104 bytes, in a private directory of the user's own under the system's temporary one.
    phase-outcome.sh refuses a malformed unit: ref.
  • A date beside a live ref is a backstop (#181). waiting-external --watch <ref> --watch date:<iso>
    wakes the phase the moment the ref lands; the date only bounds the wait, and if it passes first the
    phase is resumed told that the ref has NOT landed and what it last read (phase.waiting carries
    backstop). The script says which ref is the backstop when it records the declaration.
  • A plan raises its own wait count (#40). **Wait count:** <n> in §Session budget, or
    - **Wait count:** <n> on a phase (1–99), lifts the four declared waits a phase may spend;
    phase-graph.sh --wait-count [N] reads it, wait-budget.sh [--phase N] --count <n> writes it. A park
    on a spent count or a spent time budget whose watch ref still polls now reads as a WAIT on that ref —
    the run waiting on it, looked at again every six hours — never an errand to re-check it by hand. A
    date: is a clock, not such a ref, and a ref the watch clock has refused for good no longer counts:
    either way the park is a person's again, with its budgets errand. The session contract states the
    raised count and where it came from.
  • The operator's acts, as one queue (#182). A seventeenth human-step kind, operator-act — an act
    only the operator does, a command to run or a click path to follow — and a ninth state, upcoming,
    first in the path: a step declared with a due-when ref is shown under Coming up, unannounced and
    unreminded, its window not started, until that ref lands; then it is due with ONE notification,
    NOW: <command>, and its proof landing clears it and resumes the phase that needed it. A session
    declares one with phase-outcome.sh … needs-human --act --due-when <ref>; a plan with a due: <ref>
    field on its - **Human step:** bullet, in a phase or under ## Operator errands (the plan's own,
    phase 0). A due: that fits no scheme's shape fails the F37 lint by name. While an act is coming up
    its park summons nobody — no needs-you push, no errand row — and a due-when ref the console refuses
    makes it due at once, the refusal named; a frozen console asks no due-when ref at all. The approve page
    and the Tower list Coming up after what is due, each row with its command to copy. New journal line
    phase.human-step-due, log human-steps.due.
  • The Issues desk (control-tower phase 118). Repo ▸ Issues reads a repository's WHOLE issue list:
    one gh issue list --state all with a cap of 2,000 (ISSUE_LIST_CAP, asked one over so truncated is
    measured, never assumed), with author, createdAt and closedAt now among the fields and still no
    field that returns a body. Each issue carries what the desk reads off it, derived once in
    viewer/shared/issues-model.js (categoryOf, severityOf, planStateOf, triageOf) and drawn
    through the status family: its category (bug · enhancement · documentation · question ·
    other), its severity (a severity: label, or none) and where it stands in a plan — needs a plan
    (awaiting-plan), planned in <slug> phase N (plan:<slug>, with the phase a local plan's Fixes:
    line names), deferred (plan:<slug>-deferred), fixed (closed, with a plan label). Every column sorts
    and the sort is in the URL beside the new Category, Severity and Plan status filters. The repository
    picker takes any GitHub owner/name an operator adds (prefs.issueRepos, at most 12), read and
    refreshed like the estate and marked "outside this console". The palette's entry is "The Issues
    desk", and the Plans page links "Plan from issues" to it.
  • The issue rubric's words (control-tower phase 114). viewer/shared/issues-model.js owns the
    three issue types (bug · enhancement · documentation), the four severities worst-first with their
    one-line meanings (critical — data loss, a security or permission bypass, an unapproved production
    change, or every lane blocked; high — a run halts or parks, or reaches a wrong verdict, with no in-run
    workaround; medium — time or money wasted, a workaround exists; low — cosmetic, wording, noise), the
    lifecycle labels awaiting-plan and from-session with the severity: prefix, and the suggestion
    words; scripts/issues.env is their bash twin, held word for word by gates-vocab.test.ts.
  • The docs say what 6.1 adds, in English and Persian (control-tower phase 122). The help sheet's
    Halts section gains A job on another machine (the unit: watch and its hosts.<name> profile
    entry) and its watch card the date backstop and the raised wait count; Your turn gains Acts that come
    due later
    (operator-act, Coming up, due:, --act --due-when); Getting around's Repo card says
    what the Issues desk reads off each issue; When stuck ▸ Parked explains a run that is done but not on
    its trunk (unlanded). README and USAGE carry a 6.1 paragraph each and their Persian twins the same,
    viewer/README.md and its twin state the 6.1 wait rules, and docs/loop.md's scheme table gains
    unit:.

Fixed

  • A temp-file save under docs/ no longer makes the console forget every plan (#244). An editor's or
    an agent's atomic write reached the plan store as a change that named no plan, so the console forgot
    every plan and read them all again, and hung while every board was derived anew. The watcher now drops
    temp-file and atomic-save artifacts before they become a change, and a change forgets only the plans it
    moved or named.
  • A plan card's repository tag keeps its width on a phone (control-tower phase 118, #203). At 360 px
    a range estimate and the time filled the card's meta row, and the tag — the one part allowed to shrink —
    gave way to zero pixels. The row now wraps the tim...
Read more

v6.0.0

Choose a tag to compare

@zsarir zsarir released this 01 Oct 12:22

Control Tower. 6.0 makes an unattended run something a person can read at a glance and trust to
say when it needs them. The console's home is the Tower (#/runs): what needs you, what is
moving, what waits and what is next, each strip one sentence and one action, and amber only when a
person must act — a status word alone never paints it. A run that stops itself says why in one card
and comes back with one press; a failure is a failed phase, a declared wait is a wait, and a resumed
phase keeps its seat, its settings and its session. A person's turn — a sign-in, a code, an approval
at the machine — is a typed step with its own card and its own proof. The plan page is one phase table
with four views and a route map that holds seventy stations; runs, sessions, the repository and the
numbers were rebuilt on one data grid, one status model and one design law. Quick start is one screen,
and the guide explains every page in English and Persian. The free tree stays MIT. It is a major
version because the home, the plan page's tabs and the colour law changed under people's feet — the
list is below.

Migration

  • The home is the Tower. An empty or unknown address opens #/runs, and #/now and #/dashboard
    redirect there, keeping whatever half of the address still means something. A bookmark, a handoff
    link or a notification from 5.x still lands.
  • A plan page has three tabs — Phases, Run, Source. The four lists that were Route, Phases, QA
    and Handoffs are the Phases tab's views (?view=table|map|qa|handoffs); the old tab addresses
    redirect into them.
  • Amber is a summons, never a status. A board stuck phase reads Stuck in the waiting paint
    with an alert glyph; halted, parked and gated read as waits. Anything that asked you for
    something still turns amber, through its inbox item.
  • A - **Human step:** bullet in the 5.1.0 <who, what, proof ref> spelling fails the lint (F37).
    Write the six-field grammar (references/plan-format.md) or leave the label off.
  • The failure streak counts failed phases, not endings. The same phase failing twice is one
    failure, and a refused credential or a lost network never counts.
  • The decision manifest has nineteen keys — issues and plan-approval joined the seventeen.
    A plan that answers neither keeps the shipped defaults (off and hold).
  • Update the console's scripts and the plugin together, as at 5.1.0: a 5.1.0 phase-outcome.sh
    rejects needs-human --step, and a 5.1.0 phase-graph.sh has no --human-steps arm.
  • The console's heap is a number it chooses. viewer/run passes --max-old-space-size as a node
    argument — never NODE_OPTIONS, which every claude child would inherit — from heapMb in
    ~/.config/phase-console/fleet.json (6144 by default), clamped to half of RAM. A console started
    some other way keeps V8's default heap until it is started through viewer/run again.
  • For forks of the client: the 2.x Chip, its tones and the --line-* / 2.x colour aliases are
    gone; badges are the typed status family under components/ui/status/, and ESLint refuses a raw
    StatusBadge import outside it.

Added

  • The guide explains every page, in English and Persian (control-tower phase 32). The help sheet
    gains four sections — Quick start, Getting around (a card for every page on the rail and every
    overlay), Tower and Halts — and every section now has a Persian twin beside its English body
    (viewer/client/src/content/guide/<id>.fa.md), held to the English section for section by
    docs-parity.test.ts and required by guide-coverage.test.ts, which also fails a page or an overlay
    that has no card.
  • A person's turn has a language (control-tower phase 41; operator decision 7). An act only a
    person can do — a sign-in that opens a browser, a device code, a token to paste, a password at the
    machine, an approval on somebody else's dashboard — is a HUMAN STEP: one of sixteen typed kinds
    (viewer/shared/human-step-model.js, twin scripts/human-steps.env), eight states, and KIND_META
    as the one place a kind's icon, label, default where and proof hint are read. A session declares
    one with phase-outcome.sh … needs-human --step <kind> --title … [--open-url | --open-command] [--where] [--proof] [--step-line]… [--code] [--credential]; a value shaped like a token, a password,
    a one-time code or a URL query secret is refused with nothing written. A plan declares one with
    - **Human step:** <kind> · <what> · open: … · proof: … · where: host|any · window: … [· auto-open: host], read by phase-graph.sh --human-steps [N] and its JS twin; the 5.1.0 <who, what, proof ref> spelling, which nothing ever parsed, is superseded and fails the lint by name (F37), and a step
    with no proof is advised about (F38). The console writes each step to an append-only ledger
    (human-steps.ndjson: last state wins, a torn last line dropped, a retention sink), raises ONE
    human-step inbox row and ONE needs-you push naming Open and I did it (and a device code),
    and parks the phase on a PERSON — an unbudgeted wait, situation blocked-declared:human-acts, no
    rung. No code, token, password or URL query secret reaches the ledger, a journal line, a push
    payload, the log or a transcript; a secret-entry secret goes to the credential registry (the
    keychain, else a 0600 file) and is never read back.
  • A person's turn can be acted on (control-tower phase 43; operator decision 7). Six routes —
    GET /api/human-steps[?open=1] and POST /api/human-steps/:id/{open,check,snooze,cannot,dismiss},
    each a move through the ledger's one door, attributed, journalled (phase.human-step-opened,
    -checked, -proven, -snoozed, -cannot, -dismissed, -expired, -reminded). Open
    answers the link for the caller's browser, or opens it on the machine behind --allow-terminal /
    --allow-agent only once the caller has sent back the full URL it was shown; a command step opens
    the embedded terminal, which prints the command and runs it on the person's Enter, and nothing
    typed there reaches the ticket, a journal or the ledger. Open again is unlimited short of a settled
    step. A step's proof is a WATCH ref, polled off the declaration on the cmd: back-off and bounded
    by the step's window (seven days when it names none), never by a wait budget; when it lands — or
    I did it — check finds it true, a terminal's exit 0 proves a step with no proof ref, and a person's
    word one with no proof at all — the step reads proven and the SAME session is resumed told what
    was proven. An unlanded check says what the proof read, in its own words. Reminders at +15 m, +1 h,
    +6 h, then daily, deferred out of the new reminderQuiet hours and past a snooze, replace the
    step's notification; at the window's end the step expires into an errand, and I can't do this
    becomes one at once carrying the reason — neither loops. I did it is a signed notification button
    (check in PUSH_ACTION_VERBS), and the step's inbox row offers check, snooze and cannot.
  • The console notices a person's turn (control-tower phase 44; operator decision 7, its third
    birth channel). The sign-in guard: a supervised Bash call that starts an interactive sign-in
    (SIGN_IN_SHAPES — gh auth login, az login, npx wrangler login, … through wrappers,
    sudo, package runners, env prefixes, groups and chains; never a here-doc's data) is denied
    before it runs on every profile, phase.tool-denied rule sign-in, with the whole
    needs-human --step … declaration to make instead (SIGN_IN_STEPS: the kind, and the tool's own
    status verb as the proof only where the console's command judge runs that tool — gh, npm,
    pnpm, yarn; a password given with -p never reaches the journal); a status verb (gh auth status) and a sign-in with a non-interactive
    flag (--with-token, --password-stdin, --identity, …) run, and a call no run token names is
    untouched. The stall reading: a silent lane whose last output named an http(s) link beside
    waiting words (SUSPECT_WAIT_WORDS; "open this link in your browser" counts only for a link that
    is not the machine's loopback) carries suspectedStep and journals phase.human-step-suspected;
    its inbox row is raised at once, offers Make it a person's turn
    (POST /api/human-steps/suspected, phase.human-step-converted, a step born console; a second
    press answers the same step) and never converts or opens anything by itself; the reading is made
    over a result's whole text, and neither its link nor its words ever carry a device code. The launch door: probe 9 lists the plan's
    - **Human step:** bullets for the phases the run will drive, runs every proof at once through
    the watch clock's own probe, pre-clears the proven and returns the rest with their open actions
    (Prelude.humanSteps); a start records the owed ones in the ledger, born plan, just before the
    runner starts, and the reminder clock withdraws one once its phase's handoff reads complete. The folds:
    every inbox row that asks a person for an act carries one humanStep view (humanStepView,
    HUMAN_STEP_FOLDS) — a sign-in as claude-login, an MCP sign-in as mcp-login, the verification
    card as person-check, a plan to approve, a gate, a relayed question and a QA verdict as
    decision, phase 39's protected path as protected-path with the act and the path the session
    named (Errand.step) — and os-permission names its settings pane, physical carries a QR for
    its link.
  • Runs is the Tower (control-tower phase 20; the operator's "a full live management page for
    runs", and #19's fence made visible). #/runs answers "does anything need me?" in one look: every
    run sits in exactly one bay, most urgent first — Needs you, Live, Waiting, Queued, Ready to start,
    Settled — read off the status model, s...
Read more

v5.1.0

Choose a tag to compare

@zsarir zsarir released this 22 Sep 05:38

Many plans, one repository. Several plans can now work one repository at the same time without
treading on each other: each run in a checkout of its own, locks two processes cannot both win, one
trace id through everything a run does, and notes that reach a phase before it starts. It is a minor
version because it is additive — a 5.0.0 plan lints and runs unchanged, and every new door stays
closed until a plan directive or a capability flag opens it. docs/releasing.md, §Upgrading to 5.1.0,
is the list of what an older copy will notice.

Migration

  • None. Five lint ids are new — F26 note-target-unknown, F27 land-word-unknown and F29
    landed-gate-unknown-phase fail a plan, F28 land-needs-lane and F30 note-target-done advise —
    and each fires only on a directive 5.0.0 did not have. Update the console's scripts and the plugin
    together, as at 5.0.0: a 5.0.0 phase-graph.sh has no --notes arm and a 5.0.0 phase-outcome.sh
    rejects --for.
  • One tightening. Nine shared-.git verbs (git stash, config, worktree, submodule,
    checkout, switch, and gh issue create/comment/close) now raise a permission card on every
    profile: one of them in a shared checkout is another lane's problem.

Added

  • A checkout of its own, per repository. A run's branch forks from the trunk at a pinned sha and
    records who chose the base; the console's worktrees are git worktree locked with a reason naming the
    console, the plan, the phase and the time, and sweeps unlock only the console's own stale locks. A
    retention word — keep-on-failure (the default) · prune · keep · ttl:<h> — says what becomes of
    a checkout when the run settles, and a dirty tree is never removed. A per-repository cap bounds how
    many isolated runs stand beside each other, .worktreeinclude copies ignored-but-needed files into a
    fresh worktree, and - **Isolation:** shared|worktree lets one phase carve itself out.
  • Locks two processes cannot both win. A claim is made with ln, which the filesystem makes
    atomic; a lock with no scope= line reads as all everywhere; the runner claims provisionally at
    grant and stops the lane on losing the lock rather than editing on; the unsupervised outcome inbox
    stamps its filenames so a second declaration never destroys an unread first; run ids are twelve hex
    characters.
  • Worktrees, lanes and settles that tell the truth. The run pruner reads the phase list from disk;
    merges into one tree are serialised per directory; a vanished lane directory is rebuilt and a drifted
    mirror mount is named and reattached; a settle that ends on a usage wall no longer claims the branch
    was published.
  • One trace id, one seam under every child process. A run's trace id rides the HTTP request, the
    drive, every phase attempt, the spawned session, the scripts, the presence hook and every git command;
    one module is the seam under every child and logs its argv, cwd, ms and code. The log
    envelope is v2 with a debug level, PHASE_CONSOLE_DEBUG=<channel> admits one channel at debug,
    /api/debug/level flips it on a deadline, and a journal at its cap writes an in-band journal.full
    marker and keeps a reserve so run.finished is always reachable.
  • Nothing grows without a bound, and one run exports as one file. A retention planner sweeps
    transcripts, task ledgers, outcomes, git traces and the supervisor's stdio by a table Settings ▸ This
    instance ▸ Logs and retention can preview before it acts; rulings are never pruned. Each session's raw
    hook payloads are kept beside its record, capped at 1 MB with one marker line. GET /api/debug/bundle?slug=&run= answers one run as a redacted tarball, and phase-console diagnostics --run <id> builds the same thing with no console up.
  • --allow-publish, the eighth capability flag. Off by default like the other seven, it is what
    lets the console push a finished phase's pe/* branch — never a trunk, never with force — and file
    issues on the repository's behalf, where a plan's permission.destructive row allows the act.
    phase-console doctor gains a non-blocking publish row.
  • Notes reach the phase that needs them. A handoff bullet addressed forward and a deferral ruling
    (phase-outcome.sh … ruling --kind deferral --for <M|next|all>) are collected by
    phase-graph.sh <slug> --notes N into that phase's boot prompt, shown on the plan page, and linted
    (F30) when addressed to a phase that has already finished.
  • The contracts. Three new vocabularies with bash twins (landing, messages, issues); the plan
    directives --land, --landing, --base-branch, --gitlink, --conflict-policy, --isolation,
    --clash-zones, --issues, --messaging and --notes, each answering word · phase|plan|default;
    two self-evaluating gate kinds, landed N and pr-merged N, that read a ledger and run nothing;
    scripts/phase-landing.sh, the ledger's writer; and an eighteenth decision key, issues.
  • The verification launch door. Every §Verification command a run would stop on is answered
    once, at the start door: the prelude's fifth probe, verification, lists each by exact text, phase
    and reason, to approve (bound to a hash of its whole text) or waive for the run; one verification
    review answers boarding, the start response, the plan page, plan health and the repair gate alike.
    The launch form says what each phase will run as and where the plan and the run differ; context is
    counted per call (412K ctx · peak 455K · 2 rebuilds · 17 polls) and a session is told to wrap up
    at 0.6 × its window; live spend shows beside booked spend.
  • doctor probes git under the console's own PATH, blocking — under launchd that path led to
    Apple's git shim, which exits 69 until the Xcode licence is accepted.
  • bootedAt on /api/state — the process's identity, so the page that pressed Restart reloads
    once a different one answers.
  • Smaller things. Base branch, "Runs beside it in the repository" and "When the run settles, its
    checkouts" on the launch form and in Settings ▸ Automation; a Land: chip and a locked chip on the
    run and Now pages; a per-action words box on inbox rows; refusalReasons on GET /api/state;
    "Serialise conflicted branches" and "Call it looping after" among the automation preferences.

Changed

  • One wait procedure, in every place a session meets it, and a runaway run of status checks
    (six inside two minutes with nothing else between) is refused at the hook with the procedure.
  • A session is resumed only while it is worth resuming — one that ended at ≥ 250k tokens and is
    cold, that declared partial --reason budget|context, or that the console checkpointed is boarded
    fresh with the resume brief.
  • A nearly spent account stops taking on lanes, and a usage wall that cannot clear soon is waited
    out at the first burst rather than after twenty minutes of retries.

Fixed

  • A fresh run carries the start door's maxParallel — it reached a continued run and never a new one.
  • bats is a command, git merge-base/merge-tree are reads, 2>&1 is not a separator, and
    ! grep … is judged as the command it negates; a $(…) inside double quotes is judged too, and a
    backgrounded cmd & no longer reports green without waiting.
  • The self-heal no longer dead-ends or buys a session for an approval, and a Person-check: halt
    park names the refused command and the remedy that exists.
  • Every turn of a multi-turn session is booked; a phase this run worked is no longer called
    "closed outside this run"; phase-console stop reports a console stopped when its process has left;
    a hung server test fails by name; a terminal left open no longer holds the autopilot.
  • The findings 5.0.0 left open, each ended in one state: a generated prompt names the docs root it
    was read from; the recovery panel stops offering a resume the policy refuses; a wait-resume onto a
    lost session boards with the resume brief; a pull request is no longer cancelled by a declined
    resume; the local-job nudge waits out the window the procedure grants; paging a file is not a poll;
    a closeout that could not resume says why in English; preFirstTurn asks what this session spent.

v5.0.0

Choose a tag to compare

@zsarir zsarir released this 16 Sep 00:55

Zero-touch: what a run would stop to ask is asked before it starts. This is a major version
because a plan, a session and a script that starts runs each meet something that now refuses.
docs/releasing.md, §Upgrading to 5.0.0, is the full list.

Migration

  • Three lint ids now fail a plan. F14 verification-empty-open: give every open phase's
    §Verification a runnable command. F24 gate-directive-missing: put a - **Gate-check:** line under
    every *(GATED)* heading. F25: every outstanding row in ## Decisions names an owner, a known key
    and a known state. Lint every live plan with the 5.0.0 scripts before a console runs it.
  • phase-outcome.sh … blocked|needs-human requires --needs <key|class>. A 4.1.0 copy of the
    script rejects the flag, so update the console and the plugin together.
  • A run started over HTTP must carry resumeOnRestart, relay and accounts (400 without them).
    It is refused with 409 while a blocking decision is still open, a waiver is unacknowledged or a
    probe fails.
  • Defaults and names moved. delegateHumanGates now ships on and qa.exhausted answers waive.
    phase.tool-auto-granted is now phase.approval-auto-granted, and phase.resume-at-boot is now
    phase.resume-automatic.
  • The relay needs claude 2.1.268 or later. Sessions that are not relayed run with
    --permission-prompts none from 2.1.259.

Added

  • The decision manifest. ## Decisions has seventeen keys; read it with
    phase-graph.sh --decisions and answer it with scripts/decisions.sh.
  • The run-start prelude. Four probes run before anything spawns: accounts, MCP servers,
    credentials and a delivery channel. phase-console doctor runs the same probes by hand.
  • The policy table and ruling memory. Eighteen kinds of interruption are answered by default and
    journalled. --remember promotes a ruling into the next plan, and the table is edited under
    Settings ▸ Automation ▸ Policy.
  • The relay. A question a session asks is held for sixty seconds, then answered by rule, else the
    recommended option, else the first. It is never answered on a deny-list match.
  • Honest sessions. Every stop sends SIGINT first, so turns and cost are booked. Every session
    carries a turn cap and a dollar cap, and every automatic start names its door and counts against a
    ceiling.
  • Honest waits. A declared wait longer than the console's budget is refused with the arithmetic
    instead of being cut. Every resume checks that the session is not live, and an overdue clock at boot
    is ruled on rather than fired.
  • Accounts at the wall. A credential an organisation refuses is retired for every console on the
    machine. The run climbs to the next account, or parks the phase with one errand.
  • An off switch that stays off. Shut down lists what is running first, and Stay off holds every
    later boot until it is cleared. phase-console sessions ingest records session presence with no
    console up.
  • Delivery. A console with no device to notify says so, and an unattended start with no channel
    asks for an acknowledgement.
  • Why a run started and what it cost, on every run and session page, reconciled against the run's
    spend.

Changed

  • The documentation describes all of the above — docs/, the references, SKILL.md and the
    in-app guide, in English and Persian.