hooks/triage_check.rb and the Servers project heuristic/board-ensure
generalization already landed in f9a81a1 but the triage hook was never
registered in hooks.json, so it could never fire. This wires it in
(second SessionStart command, 8s timeout) and adds the missing test
coverage: TriageCheck's needs-triage/note-composition logic, an
arbitrary-project (Servers) BoardEnsurer case, and the ~/servers
resolver-ambiguity fix. Also reconciles session_start.py's pull-beats-push
docstring with the new hook's sanctioned exception, and fixes a stray
comment-indent bug in board_ensurer.rb. Suite 128/282/0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PLudjwx2GWw8CFdYaBzVzK
Backlog::ProjectIndex at ~/.cc-os/projects.json, upserted fail-soft by
config-write, queried via new 'projects' subcommand. Discoverer template +
filing mechanics reference doc; CROSS-PROJECT rule line in the SessionStart
note. ADR-0034 Accepted. Suite 112/233/0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CLeMz48rvG3s9XpAsDxeho
inspect fetches remote-issue metadata (fail-soft) and emits issue_shape:
sequential-chain|flat-adhoc|mixed|null via a pure classifier. Route step 2
rewritten as three branches with split as the default for spec-shaped issue
sets (one tracker key, no migration); step 3 never-re-trigger exception;
boundary rule cites ADR-0033. Suite 103/212/0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CLeMz48rvG3s9XpAsDxeho
- Backlog::BoardResolver with injected config read/write; Cards does no filesystem I/O
- board_id honored only for planka: trackers; id hit validated against returned board
name; 404/mismatch/cache failure degrades to name lookup and rewrites the cache
- comment-preserving Config.set mirrors os-status's writer (Config.merge not used)
- FakePlankaClient boards.get 404 support; 14 new tests; suite 90 runs / 0 failures
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CLeMz48rvG3s9XpAsDxeho
Adds card-move over planka-api Cards#move; ownership rules enforced in
lib (never Next, never hitl, never out of Done, Done only for
afk-ready). afk-ready cards now skip Review per user decision; semi
still stops at Review. Skills updated to "working a card means moving
it". Suite 68 runs/153 assertions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QBAYNm4AmczQaEHfXwai5a
Config parsed/wrote YAML while os-status owns the file as key=value
lines, so config-write output was invisible to the tracker-configured
check. Now reads key=value (legacy 'key: value' lines still accepted)
and merge emits key=value.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUyiRB4vHaRkhYKUdoMW2P
os-status (#21): fix skill orchestrates remediation of failing checks via a
new hooks/checks.py --json runner; remediation pointers on every Check; new
project-graph-present and config-version-current checks; version= stamping
in .cc-os/config; banner names /os-status:fix as the single entry point.
Suite 64 tests (was 36).
os-backlog (#14): route skill (inspect + config-write subcommands,
lib/backlog/tracker.rb + inspector.rb); destination choice and live-history
migration are named human gates; Config.merge preserves other keys. Suite
54 runs / 110 assertions (was 35). Rollout (onboard cc-os, then one more
project) still pending, so #14 stays open.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUyiRB4vHaRkhYKUdoMW2P
Cards#snapshot again emits all 19 Types::Card fields (camelCase) plus
labels — 8df0cb7 had narrowed it to 8 keys, dropping listChangedAt and
silently breaking board-audit's stale-Doing check. A regression test
now pins the complete key set (35 runs green). implementation-status
records the 0.2.0 typed-returns migration and the live end-to-end
verification against the real Planka board (run on ovh-vps 2026-07-10).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BS59Nkb7fvJMFB9dZiwZ7H
0.2.0 returns Planka::Types value objects instead of parsed-JSON
hashes. Replace all hash access with typed accessors, rebuild
Cards#snapshot output as explicit string-keyed hashes (JSON output
stays byte-compatible, so skill/agent contracts are unchanged), and
rewrite test fakes on real Planka::Types records. 34 runs green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014GjXD4ZDsucFZXNgVVrnZB
Two agent definitions. card-triage batch-labels raw Backlog cards with
one priority (P0-P3) and one autonomy (hitl/semi/afk-ready) label —
label changes only, ambiguity defaults to hitl. board-audit reports the
four drift classes (stale Doing, WIP over cap, Waiting unblocked, aging
Review) and writes at most one comment per drifting card. Both
definitions state the column-ownership constraints: never move cards
past Review, never pull Next, never touch Done.
Supporting read/write primitives: Cards#attach_label + Cards#comment,
exposed as card-label / card-comment subcommands alongside the existing
read-only snapshot JSON. Fake-client unit tests, no live API.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XknQRvihHDpYE47RTmUR4N
/os-backlog:capture resolves repo -> board via the pure resolver, runs
board-ensure transparently when the board is missing, and creates the
card at Backlog only. /os-backlog:list is strictly pull-based — board
state is never injected unasked. Both skills state the column-ownership
rules (create at Backlog only, move Doing -> Review at most, never pull
Next, never move Review -> Done, never self-assign hitl cards) and fail
soft when the gem/Planka is unavailable.
New Backlog::Cards lib class + card-add / cards / snapshot subcommands;
fake-client unit tests, no live API. Manual live verification is still
pending: the planka-api gem is not installed in this environment.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XknQRvihHDpYE47RTmUR4N
Pure repo -> board decision function (Backlog::Resolver) plus the
`resolve` os-backlog subcommand: given repo path, .cc-os/config contents,
and a board-name inventory (all passed in — no filesystem or network
access in the resolver itself), returns exactly one of "use <board>" /
"activate <archived board>" / "stop-and-discuss". An explicit config
board takes precedence; otherwise the board name is derived from the
repo/client dir basename with project inferred from ~/dev vs ~/clients.
Unmapped paths, and configured-but-unmatched boards, both resolve to
stop-and-discuss rather than silently falling back. Pure Ruby unit tests,
no network.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XknQRvihHDpYE47RTmUR4N
Idempotent board-ensure over the installed planka-api gem: uniform lists
(Backlog/Next/Doing/Waiting/Review/Done), uniform label set (P0-P3, hitl,
semi, afk-ready) with per-label color-candidate fallback since Planka's
color whitelist isn't documented, the archived--<name> rename convention
(activate/archive primitives; ensure never archives automatically), and
the bot-created-project visibility fix (shared-type project + explicit
project-manager add + null ownerProjectManagerId). Unit tests stub the
client layer entirely — no live API calls.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XknQRvihHDpYE47RTmUR4N