POLICY.md codifies runtime behavior rules (no network on default
launch path), dependency vetting, vendored binary rebuild process,
telemetry prohibition, and licensing requirements. Binding on all
contributors including agents.
Line length 160 in .editorconfig (all files) and
analysis_options.yaml (dart formatter).
Co-Authored-By: Claude <noreply@anthropic.com>
Vendor libtree-sitter.so (v0.26.8, wasmtime 44.0 statically linked)
and call its C API through dart:ffi. Grammar WASM files are loaded by
tree-sitter's embedded wasmtime engine via ts_wasm_store_load_language.
48 grammars compiled with tree-sitter build --wasm, 48 highlight
queries (42 from upstream repos, 6 written in-house for comment,
erlang, gdscript, gitignore, hcl, hlsl, swift). SQLite grammar
replaces full SQL (974K-line parser exhausted RAM at compile time).
Removes wasm_run and wasm_run_flutter — they downloaded a 22 MB
binary from GitHub at first launch, violating the no-network-on-
default-launch-path policy.
Co-Authored-By: Claude <noreply@anthropic.com>
Core frame builtins are infrastructure the shell can't function
without. Content extensions (editor, claude, canvas, etc.) are
bundled but architecturally removable — users swap the surface,
not the data.
Removes builtin.jira stub: Jira belongs as a third-party
extension, not a frame builtin. Git is a split component —
daemon-side process stays in frame, UI surfaces are extensions.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 41s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Larger wordmark (48px), START section header, icon-prefixed
action rows for Open project and New Claude session. Semantics
hint preserved for a11y.
Co-Authored-By: Claude <noreply@anthropic.com>
The discard button in the git panel now opens a dialog warning
that changes will be permanently lost. Prevents accidental data
loss from a misclick.
Co-Authored-By: Claude <noreply@anthropic.com>
git.branches and git.checkout IPC verbs. Status bar shows current
branch with ahead/behind count; clicking opens a branch picker
dialog for checkout.
Co-Authored-By: Claude <noreply@anthropic.com>
ClidePalette renders as a floating overlay with fuzzy-filtered
command list. Ctrl+Shift+P toggles it. Ctrl+B toggles sidebar,
Ctrl+J toggles context panel. All wired through CommandRegistry
via the default layout extension.
Co-Authored-By: Claude <noreply@anthropic.com>
Four new icon painters (git branch, search, terminal, warning).
ClideIconRail widget with parent-owned hover state so only one
icon highlights at a time. Sidebar slot renders content above +
icon rail below; workspace and context slots keep the tab bar.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 40s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
PID file at /tmp/clide-daemon-<uid>.pid replaces pkill pattern
matching. make run depends on stop so stale daemons are killed
before build. Flutter exit via ctrl-C no longer aborts Make.
Co-Authored-By: Claude <noreply@anthropic.com>
Surface map now tries palette keys (bgSunken, surfaceHi, textHi,
etc.) first, falling back to semantic refs for legacy themes.
Sidebar/panel bg differentiates from workspace bg. Buttons use
accent colour with onAccent text. Four-level text gradient flows
to widgets.
WCAG-AA contrast fixes: clide textDim lightened, midnight
onAccent darkened, paper textDim darkened. Contrast test updated
to cover all four themes. Resolver tests updated for the new
palette shape. Goldens regenerated.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 40s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Kill stale daemon before build to prevent "Text file busy". Trap
EXIT + INT + TERM for reliable cleanup on ctrl-C. Add make stop
for standalone daemon kill.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 39s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
SurfaceTokens gains seven syntax-role fields (keyword, type,
string, number, comment, method, punct). Theme loader parses
the syntax: YAML block and injects values into the surface
override layer. Resolver defaults map syntax roles to semantic
colours so themes without explicit syntax blocks still compile.
Four new theme YAMLs (clide, midnight, paper, terminal) replace
summer-night. Palette keys mapped to the existing semantic layer;
syntax values pass through directly. Goldens regenerated for the
14→font-size change.
Co-Authored-By: Claude <noreply@anthropic.com>
New tokens/ directory with YAML palette + syntax files for all
four themes, plus a pure dart:ui Dart file (no Material). README
updated to reflect the no-Material constraint and open typography
question.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 41s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
D-043: adopt token palettes from design, reject Material wrapper.
D-044: four bundled themes replace summer-night.
D-045: syntax highlighting tokens in the theme pipeline.
Q-025: body text face — mono everywhere vs Josefin Sans + mono.
R-012: MaterialApp wrapper rejected (conflicts with D-007).
Co-Authored-By: Claude <noreply@anthropic.com>
Four self-contained HTML mockups (wireframe, flows, hi-fi, design
system), four Dart theme files (clide, midnight, paper, terminal),
and flat PNG renders. Reference material for the UI build — not
runtime assets.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 41s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Replace Flutter default icons across Linux (GTK window icon via
bundled asset), macOS (AppIcon.appiconset all sizes), and web
(favicon, PWA icons, manifest, meta description). Logo PNGs at
16–1024px generated from the SVG source. Window title set to
"clide" everywhere. Web manifest colours match summer-night.
Co-Authored-By: Claude <noreply@anthropic.com>
Builds the daemon binary if stale, starts it in the background,
launches flutter run -d linux, and cleans up the daemon on exit.
Co-Authored-By: Claude <noreply@anthropic.com>
Sidebar and panel text was too small — dozens of bare fontSize:
10/11/12 values fighting the ambient DefaultTextStyle. Root font
bumped from 13 to 14. Three semantic constants replace the magic
numbers: clideFontBody (14), clideFontCaption (12), clideFontMono
(13). Widgets that render body text now inherit instead of
overriding.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 40s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
PqlExtension contributes a sidebar tab (files, query, decisions,
tickets views) and a context-panel tab (backlinks + outlinks for
the active file, auto-refreshing on editor.active-changed).
ProblemsExtension contributes a sidebar tab aggregating pql.doctor
and decisions.sync diagnostics with actionable hints.
Both upgraded from stubs to 0.1.0.
Co-Authored-By: Claude <noreply@anthropic.com>
pql init --with-skill=yes installs .claude/skills/pql/SKILL.md
covering vault queries and the planning surface (decisions +
tickets). Lock file tracks version + SHA-256 for drift detection.
Bash(pql) and Bash(pql *) added to .claude/settings.json so
pql commands run without permission prompts.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 37s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
GitController hydrates from git.status IPC and auto-refreshes on
git.changed events. Panel shows staged/unstaged/untracked/conflict
groups with per-file actions and an inline commit field.
DiffController renders unified diffs with line numbers, addition/
removal colouring, and a staged/unstaged toggle. Both extensions
upgraded from stubs to 0.1.0.
ClideText gains an optional fontFamily parameter so diff lines can
render in JetBrainsMono without breaking golden tests (font still
inherits from ambient DefaultTextStyle by default).
Co-Authored-By: Claude <noreply@anthropic.com>
Maps clide git status|diff|stage|unstage|discard|commit|log|stash|
pull|push to the git.* IPC verbs. Updates --help to list the new
tier-3 subcommands.
Co-Authored-By: Claude <noreply@anthropic.com>
Shell-outs to git for status (porcelain v1/v2), unified-diff
parsing, and operations (stage, unstage, hunk-apply, discard,
commit, stash, log, pull, push). IPC verbs git.* registered on
the daemon dispatcher with git.changed event emission on
mutations. 42 new core tests.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 38s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
EditorController mirrors the daemon's active buffer into the Flutter
UI. Hydrates on mount (editor.active → editor.read), subscribes to
editor.opened / active-changed / edited / saved / closed, and pushes
local edits back via editor.set-content. A one-shot echo-suppression
flag keeps the daemon's authoritative edit echo from clobbering the
caret the user just moved.
Text surface is EditableText directly — no TextField / Material
import, so D-007's "bare WidgetsApp" guardrail carries into the
editor tab. JetBrainsMono via the shared mono-family constants;
cursor + selection colours come from the theme tokens.
File-tree click now calls ipc.request('editor.open', {path}) instead
of the kernel command registry (which wouldn't have reached the
daemon). The opened file becomes active, the editor tab's controller
sees editor.active-changed, and the text content reconciles.
Linux release bundle still builds; 174 app tests + 74 core tests
stay green.
Co-Authored-By: Claude <noreply@anthropic.com>
`bin/clide` gains the single-word shortcuts CLAUDE.md's tier 2 spells
out: open, active, insert, replace-selection, save. Each maps the
flat positional argv into the canonical editor.* IPC shape. Insert
and replace-selection accept a lone `-` to read text from stdin so
piping works (`pbpaste | clide replace-selection -`).
`clide tail --events` is the subscribe mode. Same socket as the
request side; the client just reads + filters events. --filter
SUBSYSTEM or SUBSYSTEM:ID narrows the stream. Exits cleanly on
SIGINT.
defaultSocketPath() now respects CLIDE_SOCKET_PATH before XDG — the
existing override callers always had this up their sleeve (via
XDG_RUNTIME_DIR manipulation) but making it explicit unblocks
parallel test runs where each test needs its own daemon socket. The
new end-to-end CLI suite does exactly that: 5 tests spin up real
daemon subprocesses and exercise the shortcut surface through the
live IPC stack.
74 core tests pass; round-trip verified by hand (open README.md →
insert → tail --events captures editor.opened / edited /
selection-changed / saved).
Co-Authored-By: Claude <noreply@anthropic.com>
EditorBuffer + Selection + EditorRegistry hold the daemon-side
active-file model (D-006 subsystem 'editor'). Active buffer
tracking means `clide insert "…"` and `clide replace-selection
"…"` target the UI's focused file without the caller supplying an
id. Mutations mark buffers dirty; editor.save writes back to disk
through the workspace root; events fire on every state change so
subscribers can mirror.
IPC surface matches CLAUDE.md's tier-2 list + the natural extras
(list, read, activate, set-selection, set-content, close). Tests
cover open-idempotence, insert at caret, replace-selection range
swap, dirty→save→clean round-trip, close picks a new active
buffer, out-of-range selection clamping.
69 core tests pass.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 37s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Pane is now a pure data class — id, kind, pid, argv, cwd, title,
isClosed. The daemon-side PaneRegistry holds a parallel map of
PtySession keyed on id; registry methods look up both sides when
writing / resizing / closing.
The `clide.dart` barrel no longer re-exports `src/pty/*`,
`src/panes/registry.dart`, or the `*_commands.dart` modules — all
three transitively import `dart:ffi` which isn't available when
compiling to WebAssembly. The daemon entrypoint (bin/clide.dart) +
core tests import them via deep paths now. Pane / PaneKind /
DaemonEventSink / RecordingEventSink stay in the barrel since
they're pure data the Flutter app references over IPC.
Verified: `dart analyze` clean, 53 core tests green, 174 app tests
green, `make ui-smoke` compiles + serves + Playwright smoke passes,
daemon boots + ping round-trips + SIGTERMs cleanly.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 45s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Tier-0 stub flipped to the real Claude pane. Primary-per-repo
semantics: session name is `clide-claude-<hash>` where <hash> is
FNV-1a over the workspace root path, so reopening clide attaches
to the same `claude` process through `tmux new-session -A`.
Primary has no close button — closing the tab disposes the widget
but deliberately does NOT call pane.close, so the tmux session
survives until the user actually exits claude or clide is shut
down. Secondary sessions (spawned via the claude.new-secondary
command registered here, UI wiring lands next) close normally and
the pane.close cascades into tmux kill-session.
Graceful fallback when tmux isn't on PATH: retries the spawn with
argv=['claude'], surfaces "no-tmux · fresh every launch" in the
header subtitle so the user knows persistence is off.
Session-naming unit tests cover determinism + uniqueness per repo.
Full app suite: 174 tests passing.
Co-Authored-By: Claude <noreply@anthropic.com>
Captures the session-persistence + primary-vs-secondary policy
referenced from ptyc/README.md and deferred through the Tier 1
substrate work. Primary per repo (keyed on git root) survives app
restart via `tmux new-session -A`; secondaries are ephemeral and
collapse back to the primary on close; primary has no close
affordance. Daemon owns the session lifecycle, the UI just asks
pane.spawn / pane.close and observes events.
Required by the next commit (builtin.claude) which consumes this
policy.
Co-Authored-By: Claude <noreply@anthropic.com>
Flutter sidebar tab that lazy-loads the workspace tree via IPC
files.ls and refreshes subtrees on files.changed events. Click-to-
open routes through a future editor.open command; until Tier 2
registers it, the execute call no-ops gracefully.
Daemon side adds a new files subsystem:
- files.root returns the resolved workspace root (git root if
present, otherwise cwd)
- files.ls lists a directory with ignore filtering applied
- files.watch starts a recursive Directory.watch and fans
FileSystemEvents out as files.changed IPC events
- FilesService owns the watcher + ignore set lifecycle
IgnoreSet + IgnorePattern implement the common gitignore subset:
anchored (/foo), directory-only (foo/), negation (!foo), **
crossing dirs, ** at trailing position. Built-in layer hides clide-
owned dirs (.git, .pql, .clide, .dart_tool, build, node_modules);
.gitignore + .clideignore at the root layer on top per D-004. Full
multi-file ignore_files: layering from .pql/config.yaml is future
work.
11 new ignore-matcher tests + 5 files.* dispatcher tests.
Co-Authored-By: Claude <noreply@anthropic.com>
Flips the Tier-0 stub into a real extension. Contributes a Terminal
tab in the workspace slot that spawns $SHELL -l via IPC pane.spawn,
feeds pane.output events into xterm.dart's Terminal, and routes user
input back through pane.write. Viewport resize propagates via
pane.resize. Surface for disconnected-daemon / exited-shell states so
there's no silent dead tab.
Knows nothing about Claude deliberately — the Claude-specific pane
(primary-per-repo, tmux-backed, D-041) lives under builtin.claude in
the next steps.
Co-Authored-By: Claude <noreply@anthropic.com>
ClidePtyView is a theme-bound wrapper around xterm.dart's TerminalView
— token-derived TerminalTheme, JetBrainsMono as the face, Semantics
live-region label so screen readers + Playwright both hear it. The
consumer (terminal / Claude extensions) owns the `Terminal` model and
wires IPC pane.write / pane.output → terminal.write() themselves; the
widget deliberately has no IPC dependency so it stays trivially
testable.
ClidePaneChrome is the shared pane header — title + subtitle + leading
icon + trailing widgets + optional close button. The close button is
null-conditional so primary Claude panes (D-041, landing in step 7)
can render without one.
xterm 4.0.0 added as a justified runtime dep + logged in
licenses.yaml per D-042. 3 new widget tests cover header rendering,
close-button presence, and the close-tap round-trip.
Q-023 records the SSH-remote-development question so the daemon + IPC
seams don't accrete local-only assumptions during Tier 1-5.
Co-Authored-By: Claude <noreply@anthropic.com>
Implements the Tier-1 pane subsystem from D-006: spawn / list / focus /
close / write / resize / tail commands, plus pane.spawned / output /
exit / resized / focused / closed events. PaneRegistry owns per-pane
PtySession lifecycles and id generation (p_N); a DaemonEventSink seam
keeps pane code decoupled from the IPC server package.
DaemonServer.broadcast() fans events out to every connected client.
Per-client subsystem/id filtering (`tail --filter pane:p_7`) is
deferred — Tier 1 broadcasts everything and the subscriber discards.
Panes carry a `kind:` field (terminal | claude). Step 7 (builtin.claude)
adds the claude-specific pane flow on top of this generic substrate —
the subsystem itself stays neutral.
14 new core tests: registry unit coverage (spawn → pane.spawned event,
output → base64 events, write/resize/close round-trips, idempotent
close, claude kind on the wire) plus dispatcher coverage (argv
validation, unknown-id → not-found, text vs bytes_b64, etc). All 37
core tests pass in ~3s under test-core.
Co-Authored-By: Claude <noreply@anthropic.com>
PtySession wraps the ptyc helper: socketpair + Process.start + recvmsg
with SCM_RIGHTS for master-fd transfer, a background isolate that
loops on blocking read() and posts byte chunks, plus write/resize/
kill/close. close() SIGTERMs the child so the PTY's EOF wakes the
reader naturally; SIGKILL + fd close + isolate kill cover the edge
where the shell ignores SIGTERM — avoids the known Linux quirk where
closing an fd doesn't unblock an in-flight read() on it.
Env defaults stamp TERM=xterm-256color, COLORTERM=truecolor,
CLICOLOR_FORCE=1 so shells + tmux + Claude emit 24-bit sequences
that xterm.dart can render. User env (HOME / USER / SHELL) still
inherits via mergePtyEnv().
ffi: 2.1.3 added as a runtime dep — the FFI bindings for socketpair,
recvmsg, read/write, and ioctl(TIOCSWINSZ) need an allocator we're
not writing by hand. Justified in pubspec + listed in licenses.yaml
per D-042.
make test-core (ci/test_core.sh) runs the Flutter-free core tests
under a 120s hard timeout with setsid + process-group kill, wired
ahead of the fast app tests in push-check so a hung PTY test can't
wedge a pre-push. Current core suite: 24 tests in ~1s.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Successful in 1m30s
test / integration_test (xvfb) (push) Failing after 1m14s
test / bundle smoke (xvfb 5s) (push) Failing after 1m3s
test / daemon subprocess + web WASM smoke (push) Successful in 1m42s
Three sections instead of one flat list. `self:` carries clide's own
MIT license (rendered first in the About screen so the user knows
what they're running before the dependency list). `dependencies:`
covers artefacts that actually ship in the binary — JetBrainsMono,
JosefinSans, yaml. `dev_dependencies:` tracks build-time tooling
(mocktail, alchemist, flutter_lints, lints, test) for audit
completeness without polluting the user-facing About panel.
Also backfilled the two root-package dev deps that were missed the
first pass: `lints: 5.0.0` and `test: 1.25.8` (root pubspec, not
app/). Root LICENSE mirrored into app/assets/LICENSE + declared as
a bundled asset so the About screen can read it at runtime (Flutter
can't reference paths above the package root).
D-042 updated to describe the three-section split and the dev-vs-
runtime distinction.
Co-Authored-By: Claude <noreply@anthropic.com>
Every third-party artefact shipping in the clide binary — fonts,
Dart packages, native tools, bundled assets — now has an entry in
app/assets/licenses.yaml with name, kind, version, homepage, license
identifier, relative path to the bundled license text, and a
one-line purpose. The About screen (Tier 6) will render this file
verbatim. Seeded with the current set: JetBrainsMono, JosefinSans,
yaml, mocktail, alchemist, flutter_lints.
D-042 captures the two-step-commit rule (artefact + licenses.yaml
entry in the same changeset) alongside D-031's prefer-zero-deps
budget: preferring zero deps is the budget; licenses.yaml is the
visible consequence when the budget grows.
CLAUDE.md "Dependencies & supply chain" gains a matching guardrail
line. The per-dep license text files (OFL.txt for both fonts) are
declared as pubspec assets too so the About screen has something to
display, not just a manifest.
Co-Authored-By: Claude <noreply@anthropic.com>
Vendor the JosefinSans variable font (upright + italic, weight range
100-700), OFL licensed. _AppRoot installs it as the ambient
DefaultTextStyle at weight w300 (Light); ClideText inherits rather
than re-specifying the family, so Alchemist's Ahem injection keeps
goldens deterministic per D-024 while production renders the
intended face.
typography.dart gains clideUiFamily + clideUiFamilyFallback
alongside the existing mono constants; .gitignore learns about
Alchemist's failures/ diff output dir so local re-runs don't leak
into `git status`.
Co-Authored-By: Claude <noreply@anthropic.com>
Vendor the 4 core weights (Regular, Italic, Bold, BoldItalic) of
JetBrains Mono v2.304 under app/assets/fonts/jetbrains_mono/, ~1 MB
total. OFL license checked in alongside. Declared as the
JetBrainsMono family in pubspec so Flutter bundles it automatically.
app/lib/widgets/src/typography.dart exposes clideMonoFamily plus a
platform-ordered fallback chain (SF Mono / Menlo / Monaco →
JetBrains Mono system install / Fira Code / Hack / DejaVu / Liberation →
Cascadia / Consolas → monospace) for web builds and test harnesses
that don't load asset fonts. Terminal widgets pick both up via a
single import.
Co-Authored-By: Claude <noreply@anthropic.com>
One-shot helper that opens a PTY, forks a child, execvp's the given
argv with the slave as stdin/stdout/stderr, and hands the master fd
back to the caller over a unix socket via SCM_RIGHTS. Wire contract
is stdin JSON → stdout JSON + fd transfer per D-005; socket fd
defaults to 3 with PTYC_SOCK_FD override for language runtimes whose
subprocess machinery shuffles the low fd numbers.
Minimal JSON parser (no deps) scoped to the exact accepted shape.
Exec-failure pipe (CLOEXEC) reports child-side errors back without
zombies. Window size applied via TIOCSWINSZ before fork; child
becomes session leader + makes the slave its controlling TTY.
Root Makefile PTYX_PRESENT typo fixed → PTYC_PRESENT, and a
ptyc-test target added alongside ptyc-build / ptyc-clean. Eight
smoke tests pass (happy path, env replacement, cwd, window size,
bad argv, type errors, exec failure, unknown keys).
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Successful in 4m34s
test / integration_test (xvfb) (push) Failing after 1m4s
test / bundle smoke (xvfb 5s) (push) Failing after 58s
test / daemon subprocess + web WASM smoke (push) Successful in 2m27s
CLAUDE.md gains a "Decision discipline" guardrail pointing at
decisions/<domain>.md, rewrites every inline ADR link to the new
anchor-link style (ADR 0001 → D-001, etc.), collapses the bottom
"Open questions" section to a one-line pointer, and updates the
parent-project note to reference decisions/architecture.md instead
of the deleted docs/ADRs/.
Three extension slots are reserved with id-only stubs, registered
alongside the existing 21 built-ins in main.dart:
- builtin.decisions — future sidebar for D/Q/R records
- builtin.tickets — future sidebar + kanban workspace
- builtin.claude-control — future .claude/ first-class surface
(Settings / Skills / Agents / Hooks / MCP). Distinct from the
existing builtin.claude PTY-pane stub.
`flutter analyze` clean; builtin + a11y test suites still pass.
Co-Authored-By: Claude <noreply@anthropic.com>
One new Makefile target (tools/scripts/plan decisions validate)
wired as a prerequisite of push-check so malformed records fail
locally before they reach a reviewer. Parser dry-run is cheap
(~100ms) and stays within the <90s pre-push budget.
Co-Authored-By: Claude <noreply@anthropic.com>
Ports settled-reach's decisions_sync.py + ticket + decision scripts,
Scrum-stripped. Writes to .pql/pql.db (gitignored). Verb shape
mirrors the eventual `pql` subcommands so migration is a call-site
find-replace once pql ships feature parity (D-040, R-011).
Ticket IDs are T-NNN (TEXT PKs) — reshape from settled-reach's
integer auto-increment so the stopgap's writes are compatible with
pql's future reads without a data migration. No `sprints` table; the
pyramid is kanban / waterfall (D-035).
Verified end-to-end: sync parses 71 records (39 confirmed, 23 open
questions, 9 rejected) with 62 cross-refs and zero broken links;
`ticket new`, `ticket status`, `ticket board`, and `decisions show
--with-refs` all round-trip correctly.
Co-Authored-By: Claude <noreply@anthropic.com>
Adopt settled-reach's Q&D record convention. Confirmed decisions
live under decisions/<domain>.md as D-NNN; open questions under
questions-<domain>.md as Q-NNN; rejected alternatives in rejected.md
as R-NNN. Markdown is source of truth; .pql/pql.db (added later) is a
query index.
Backlog captured from the Tier-0 Flutter planning sessions: bare
WidgetsApp, theme pipeline, kernel admission rule, feature-first
layout, a11y + i18n as Tier-0 contracts, test pyramid, kanban over
Scrum, pql-owns-planning, Python stopgap sunset clause.
ADR migration (D-001, D-003-D-006 confirmed, R-002 rejected) is
staged for the next commit so the diff stays readable.
Co-Authored-By: Claude <noreply@anthropic.com>
Three docs under docs/testing/:
* README.md — layer-by-layer reference (what each covers, the
runner, how to invoke, local vs CI flow). Points at the load-
bearing startup gate and the client-side-only constraint so a
macOS clone runs the same suite as Linux.
* a11y-manual.md — 15-minute manual checklist run at every tier
cut. Orca on Linux, VoiceOver on macOS. Catches prose drift
automation can't judge.
* claude-ui-workflow.md — how Claude Code drives the WASM build
through Playwright, including the `flt-semantics-placeholder`
quirk (semantics are opt-in in Flutter web; the driver
auto-clicks the placeholder to enable them).
Co-Authored-By: Claude <noreply@anthropic.com>
Makefile grows targets for each test layer (test, test-a11y,
test-integration, test-e2e, test-all), the coverage + smoke-bundle
helpers, and the UI harness (ui-dev, ui-stop, ui-smoke). push-check
now runs `test + test-a11y` — fast pre-push gate under 90s.
ci/coverage.sh is renamed to ci/test_coverage.sh so it matches the
`test_*.sh` naming of the other layer scripts and sidesteps the
repo's `coverage.*` gitignore pattern (intended for coverage output
files like coverage.lcov, not scripts).
Co-Authored-By: Claude <noreply@anthropic.com>