---
summary: Backlog decision + pilot plan (Planka CE on OVH, live 2026-07-08, phone gate passed 2026-07-09) — Dev + Clients Planka projects with per-repo/per-client boards, kanban WIP flow with human/AI column ownership, thin Ruby gem/CLI + tick, pull-based unified dashboard (digest + SessionStart brief dropped), vault demoted to knowledge layer
tags:
  - scope/global
  - type/decision
  - domain/task-management
  - tool/claude-code
  - project/cc-os
status: accepted-pilot-live
last_reviewed: 2026-07-10
---

# Backlog system: decision and pilot plan v2 (2026-07-06)

Research behind this decision: [[backlog-system-options-research]] (including the same-day second-pass Planka deep-dive and alternatives sweep).

**Supersedes the v1 vault-native plan (same day).** v1 chose vault task notes + Obsidian Bases kanban. It was overturned within hours by a requirement clarification, recorded here so the reasoning survives:

## The requirement change that flipped the decision

The perspectives panel and v1 optimized for "push beats pull." The user corrected this: **the pull surface — a visual board viewable and interactable from anywhere, any device, any time — is the primary requirement**, not a nice-to-have. The founding pain point is "when I want to jump into a project I have no visual interface to see what's on the docket," and with ADHD a desktop-only interface means forgotten/missed tasks. Conversational access ("what's on my plate?" via chat) does not satisfy this; it must be *visual*.

- Vault-native's known weakness (dashboard maturity, mobile — Bases custom views are desktop-weak) became **disqualifying**.
- Planka's known weakness (task data outside markdown) became **"a development problem"** — solvable via REST API, per the user.

## Decision

- **Planka v2 Community Edition** (AGPL, plankanban/planka) deployed on the **OVH production server** (`systems-prod-01`, see `~/servers/ovh-prod/`), as a standard `~/services/planka/` docker-compose service behind Traefik with automatic SSL. Auto-discovered by the existing backup script.
- **Why OVH, not the home Proxmox box / hermes01:** always-on independent of home ISP/power; already reachable from anywhere with SSL (phone needs a bookmark, not Tailscale); fits the established deploy + backup pattern. Access control (strong auth at minimum; optional Traefik middleware/IP allowlist — client names will appear on cards) is a deploy-time decision.
- **No filesystem co-location with the vault is needed.** Planka state is Postgres; all integration (CLI, tick, digest, future Hermes) goes through Planka's REST API + git. Cards reference SecondBrain notes by name/URL; any host that ever needs note *content* clones the vault from Forgejo (one command). The vault does NOT currently sync to OVH and doesn't need to.
- **Vault role demoted to knowledge layer:** how-tos, contractor/client notes, conventions, decisions stay in SecondBrain; task *state* lives in Planka. The proven Notion rental pattern (item-with-references) survives split across the two: card = state + links, vault note = knowledge.
- **Forgejo issues remain the code-execution tracker** (rule unchanged: Forgejo = code/arch/deployment work inside a repo; Planka = everything else; cards may link issues).
- **CLI over MCP.** No official Planka CLI exists; we build a thin Ruby one (Sandi Metz style, `lib/` + `bin/`, mirroring the os-adr pattern) over the REST API. `plankapy` (Python SDK) is the endpoint-reference crib. Community MCP servers (bradrisse/kanban-mcp etc.) are shelf reference only.

### Repo/artifact separation + gem scope (2026-07-07 amendment)

- **Three repos, three concerns:** deploy artifacts (compose, cron wiring, config, deploy PRD/runbook) live in `~/servers/ovh-prod/`; the Ruby gem (API client + `backlog` CLI + tick/digest logic) lives in `~/dev/ruby-gems/`; cc-os carries only the SessionStart-brief plugin + its eval harness. The plugin depends on the gem's installed binary — no cross-repo source coupling. ovh-prod stays behavior-free (compose + cron + config only) so all logic remains model-free-testable inside the gem.
- **Gem is two-layer:** (1) a thin faithful **client layer** wrapping the Planka REST API broadly — core resources (projects/boards/lists/cards/tasks/due-dates/labels/comments/memberships/auth) **plus webhooks** (decided: wanted, so Planka can trigger strategic outbound actions via n8n/other APIs) and **admin + attachments** (less certain but likely useful — included in the first pass on the grounds that shipping probably-working endpoints now beats reopening the client later; Planka API churn judged low-risk); (2) a small opinionated **domain layer** (`add --quick`, `list --all`, `tick`) used by the CLI, digest, and future Hermes. Client layer generated with the `api-wrapper` skill, `plankapy` as endpoint crib. Per-credential instantiation (no global auth singleton) to support Hermes' scoped tokens.
- **PRDs drafted 2026-07-07:** deploy PRD → ovh-prod repo docs; gem PRD → ruby-gems repo. cc-os plugin PRD deferred to Phase 1 (plugin-home decision resolved 2026-07-10: new `os-backlog`, ADR-023).

### Organization + workflow v2 (2026-07-09 amendment — gate passed)

**Phone gate PASSED 2026-07-09** (Planka v2.1.1 live at planka.hyperthrive.io since 2026-07-08). The per-hat board seeding from Phase 0 is superseded before it ran; this section replaces it.

**Structure — two Planka projects, boards per unit of work:**

- **Dev** project → one board per dev effort. Initial boards: **cc-os** and **planka gem** (`~/dev/ruby-gems/planka` — gem v1 is functionally complete but never went through an organized check-off; its existing "Build" board cards get walked through Review as the first exercise of the process).
- **Clients** project → one board per client. Initial board: **philly-search-engine-marketing** (`~/clients/philly-search-engine-marketing/`). Client cards are PM-altitude: each either links a Dev board that executes it (URL in description — no first-class card links in Planka) or carries its own task checklist when too small for a dev board.
- **Property management and business-dev boards deferred** — hypothetical/nuanced; revisit after living with the system.
- Uniform **lists** on every board: `Backlog → Next → Doing → Waiting → Review → Done` (Waiting = blocked on outside input, doesn't count against WIP).
- **Labels are board-scoped in Planka**, so the CLI/seeding scripts enforce an identical label set on every board: `P0/P1/P2/P3` (priority; P3 added 2026-07-10 for the Apprise expansion cards — currently only on the cc-os board, `backlog board ensure` should adopt it) + `hitl` / `afk-ready` (AI-workability convention, adopted from the gem issue cards).

**Process — kanban with WIP limits, not agile sprints.** Capture into Backlog is cheap; pulling into Next is the only planning ritual (when Next runs dry, not on a calendar); Doing is hard-capped at 2–3 for the human; cards flow one direction.

**Human/AI column ownership:** the human pulls into Next and is the only mover of Review → Done. AI agents pull Next → Doing when pointed at work, comment progress on the card, and land finished work in Review — never Done. AI-created cards (tick recurrence, captured tasks) enter at Backlog only. `hitl`-labeled cards are never picked up by AI autonomously.

**Notification policy v2 — digest and SessionStart brief DROPPED** (mental-clutter / notification-blindness risk; pull beats push applies to notifications too). Replaced by a single **pull-based unified dashboard**: a lightweight web view next to Planka on OVH reading via the API — due/P0/Doing/Review cards across all boards, rows linking into Planka. One starting-point view, opened when the user chooses. NOT Rails — lightweight JS (à la `~/dev/thinkfast/`) or similar; details deferred to its own Planka card. The `tick` recurrence job survives unchanged (writes cards, never notifies).

**Pre-seeding audits:** before creating cards, audit each of the three initial projects to collect all outstanding items + where they're referenced in the repo (docs, TODOs, issues, PRDs), so dispatched card-writing subagents populate cards with full context and pointers.

**Tracker routing (amends the Forgejo rule):** Planka is the default target for `/to-issues` and any future `/triage` — the plugin skill resolves repo → board deterministically (board named after the repo/client dir; Dev vs. Clients project inferred from `~/dev/*` vs `~/clients/*`) and a `backlog board ensure` script creates missing boards with the standard lists + labels. Forgejo remains only where issue-linked commits/PRs in a repo justify it.

**Board lifecycle (archive/activate) — VERIFIED 2026-07-09:** live-instance API tests confirmed Planka v2.1.1 CE **cannot move a board between projects** (`projectId` is not a patchable field), cannot move cards across projects (`E_NOT_FOUND` on foreign listId), and board DELETE is permanent (cascades, no restore — never use for archiving). The Archive-project design is therefore dead; lifecycle is the rename convention: archiving = rename board `archived--<name>` + move to bottom position (ONLY on explicit human go-ahead); activating = rename back (no approval needed). Discovery via the API board listing: active board found → use; `archived--` board found → activate silently; not found for an existing repo → stop and discuss. Label CRUD verified working per board (POST `/api/boards/:id/labels`, PATCH/DELETE `/api/labels/:id`; 41-name color whitelist, no hex). Also verified 2026-07-09 during seeding: creates require an undocumented `type` field — projects `"private"`, lists `"active"`, cards `"project"`; card-label attach is POST `/api/cards/:cardId/card-labels` `{labelId}`. **Project visibility gotcha:** a bot-created project gets `ownerProjectManagerId` set (single-owner "private" mode) and is invisible to every other account — even instance admins can't add managers (`E_FORBIDDEN`). Fix/required pattern for `backlog board ensure`: after create, PATCH the project with `{"ownerProjectManagerId": null}` (as the owner; `{"type":"shared"}` is silently ignored), then POST the human's userId to `/api/projects/:id/project-managers`.

**Plugin scope widened:** the cc-os plugin (**decided 2026-07-10: new `os-backlog` plugin, ADR-023** — separation of concerns; os-vault stays memory/knowledge-only) is the AI's process-management surface and should be designed across all four plugin primitives: skills (capture/list/tick/board ops), scripts (deterministic API calls via the gem), named agents (e.g. card-triage, board-audit), and hooks (where session lifecycle genuinely helps — no push-style briefs per the notification policy).

**Execution breakdown (2026-07-09) — grouped by subagent + model tier; Fable orchestrates and reviews only. Status 2026-07-09: steps 1–3 DONE** (API verified, 3 audits run, boards seeded: Dev {cc-os, planka} + Clients {philly-search-engine-marketing}, 50 cards incl. 12 gem slices in Review and a dashboard-design card; old "planka-api gem" project left in place pending human deletion go-ahead):

1. **API verification** (haiku, 1 agent, first — everything downstream depends on it): against the live instance, test board-move-between-projects, cross-project card moves, label CRUD per board. Mechanical curl/gem calls; report findings only.
2. **Project audits** (sonnet, 3 parallel agents — judgment: what counts as an outstanding item): one each for cc-os, `~/dev/ruby-gems/planka`, `~/clients/philly-search-engine-marketing`. Sweep docs/TODOs/issues/PRDs; return itemized outstanding work with file references, suggested priority (P0–P2), and hitl/afk-ready call.
3. **Structure + seeding** (1 agent, after 1+2): create Dev + Clients projects (no Archive project — boards can't move between projects, see lifecycle above), boards per convention, uniform lists + labels; write cards from the audit outputs (no human pre-approval — 2026-07-09: human wants to see the AI's card decisions and adjust after). Since the existing "planka-api gem" project's Build board can't be moved into Dev, recreate the gem board fresh in Dev: the 12 verified-done build slices become cards in **Review** (the check-off exercise), audit findings in Backlog/Waiting; the old project is left untouched pending a human deletion go-ahead.
4. **Dashboard** (sonnet — design first as its own Planka card, then build): lightweight JS app on OVH reading the Planka API.
5. **Plugin** (sonnet build after a Fable/human design pass — the os-backlog vs. extend-os-vault decision, skill/agent/hook inventory, and tracker-routing skill are design-tier): then card-triage/board-audit named agents, `backlog board ensure` script wiring, `/to-issues` routing.
6. **tick cron on OVH** (haiku): unchanged from Phase 1.

Human gates: archive go-aheads always, plugin design decision (5), gem-card Review→Done acceptance. (Card-content pre-approval rescinded 2026-07-09.)

### Plugin home + notification transport (2026-07-10 amendment)

- **Plugin decision resolved (human gate passed):** new **`os-backlog`** plugin in cc-os, NOT an os-vault extension — separation of concerns (memory/knowledge vs. workflow/process, different stores and failure modes). Recorded as **cc-os ADR-023**, which also makes the ecosystem framing explicit: cc-os = the always-on personal operating layer (`os-*` plugins, mutually aware over time, on every machine); `~/dev/cc-plugins` = optional as-needed plugins.
- **Apprise supersedes Pushover as the notification transport (cc-os ADR-024).** Planka natively speaks Apprise; the user's services (Discord, Telegram, Bark, Home Assistant, Gnome, Zoom, Pushover) are all Apprise targets. This iteration stays minimal: Apprise API server as a docker-compose service on OVH + swap the gem's Pushover P0 for a minimal Apprise `notify` client. Expansion seeded as P2/P3 cards on the cc-os board: Apprise client gem + CLI, an `os-notify` cc-os plugin (AI-routable notifications from any session/machine), multi-service routing, Planka's native Apprise integration pointed at the same server. Notification *policy* (pull beats push, silent days silent) is unchanged — transport only.

### Fallback ladder (if the phone gate fails)

1. **TaskView** (taskview.tech) — on-paper ideal (native mobile apps, scoped API tokens, first-party MCP) but source-available, ~6 months old, thin sourcing. *Verify claims hands-on first, then trial.* Modern-and-unproven; only reached if Planka fails the gate.
2. **Vikunja** — mature API, kanban view, but mobile app explicitly alpha; revisit 2027.
3. Vault-native v1 plan (archived below via git history) / Backlog.md — the markdown lane, if hosted boards fail entirely.

**Donetick** (recurring-chore tracker, native mobile) noted as a lane-specific fallback if tick-driven recurrence proves annoying for property maintenance — resisted for now (fifth-backlog trap).

## The Planka Pro paywall and how we route around it

Planka went commercial (2025); CE keeps the full board UI. Three Pro-only features matter here, all covered by composing around the API — **we never modify or fork Planka**:

| Pro-only | Our layer instead |
|---|---|
| Recurring cards | `tick` script creates cards via REST on schedule — idempotent, elapsed-time catch-up (instantiates all missed occurrences), rules ours and portable |
| Cross-board global view | CLI `backlog list --all`, daily digest, and SessionStart brief aggregate across boards via API; in-app stays per-board (acceptable start) |
| Notification providers | The digest is ours (script-sent), Planka's notifiers irrelevant |

Known costs: "Pro discovery" banner in the free UI (cosmetic); API-token scoping story unverified (historically username/password; verify at deploy — matters for per-profile Hermes credentials; worst case a tiny API proxy enforces scope, which fits the approval-broker pattern anyway). Project health: v2 GA early 2025, tagged releases slowed since but commits continue — mature/stabilizing with a commercial turn, not dead. 12K+ stars, strong ecosystem.

## Notification policy (ADHD / notification-blindness constraint)

Three tiers, designed so silence stays meaningful:

1. **Ambient (default, zero interruptions):** the board itself + the Claude Code SessionStart brief. Information waits where the user already looks.
2. **Digest (the only routine notification):** at most ONE morning message, on ONE channel, sent **only when something is due or P0** — silent days stay silent.
3. **Interrupt:** essentially never in v1; reserved for genuinely urgent items.

Target trajectory: reminders are the degenerate case where AI can't act yet. Eventually the agent drafts the action (e.g., tenant spigot email) and the notification becomes "draft ready — approve?" — a decision, not a chore.

## Pilot plan — Fable orchestrates, cheap models do grunt work

**Phase 0 — deploy + THE GATE (day 1)**
- sonnet subagent: deploy Planka CE per the ovh-prod service pattern (`~/services/planka/`, compose + postgres, Traefik labels, temp domain first, verify backup discovery). Decide auth posture at deploy.
- haiku subagent: seed boards per hat (property, clients, cc-os/dev, business dev) + 8–10 real fixture cards via REST (spigot winterization due 2026-10-15; Woodfin HVAC/electrical/plumbing checkups; cc-os someday items incl. "adopt Storybloq handover-doc pattern"; 1–2 client items). Also proves API CRUD end-to-end.
- **Human gate — the phone test:** from the phone (responsive web; official app and Planka Pal as alternates), view boards, drag a card between lists, add a card, complete one. Pass → continue. Fail → fallback ladder.

**Phase 1 — the agent layer (parallel after the gate)**
- sonnet subagent: Ruby `backlog` CLI (`lib/` + `bin/`, model-free tests): `add --quick "title"` (defaults board/list/priority), `list --all` (cross-board), `tick` (idempotent elapsed-time recurrence catch-up from a recurrence manifest; simple offsets `+1y|+6m|+3m|+1m` only — no rule engine).
- haiku subagent: daily `tick` scheduling on the OVH box (cron or a small container next to Planka). ~~Digest~~ dropped 2026-07-09.
- ~~SessionStart brief~~ dropped 2026-07-09 → replaced by the pull-based unified dashboard (own Planka card; lightweight JS, not Rails). Plugin (skills/scripts/agents/hooks) home + naming per [[cc-os-plugin-skill-naming-convention]] (decided 2026-07-10: new `os-backlog` plugin, cc-os ADR-023; run `bin/refresh-plugins` after).
- Fable: review all deliverables; verify a fresh session surfaces the fixtures.

**Phase 2 — Hermes (independent design exercise, guardrails-first — NOT in the pilot's critical path)**
Considered separately from the task system; the task system's only obligation is integrate-ability, which REST + (verified) scoped tokens provide by construction. Design principles locked now:
- **Capability-based access:** each Hermes profile/hat (property manager, accountant, client manager, business partner) gets its own narrow, revocable credential (e.g., read-only or single-board token). Hermes never holds credentials for catastrophic actions (money movement, deletion, infra).
- **Approval broker:** catastrophic-class actions are *requests* Hermes submits to an interface (n8n workflow / API) that holds the real credentials and routes to the user for approve/reject. Guardrails are the interface, not a policy.
- Sequence: read-only digest/query first, then narrow acting (comms drafting for `property` items), one hat at a time, property manager first. Gets its own design note when started.

**Phase 3 — close-out (Fable)**
- cc-os ADR + CLAUDE.md update; retire the v1 vault-task-type idea from vault-conventions planning.
- One-week live trial. Week-2 review gates (each pre-captured as a card): digest too noisy → tighten; capture friction → extend CLI; Forgejo top-issues added to brief; recurrence annoyance → evaluate Donetick for the property lane.

**Explicitly deferred (captured as someday cards, not built):** recurrence rule engine, effort/quick-win filter, AI comms drafting, Hermes acting autonomously, vault→OVH sync, per-board polish, TaskView evaluation (unless gate fails).

## Success criteria

1. The board is viewable and interactable **from the phone, anywhere** (the gate, then daily reality).
2. Recurring tasks cannot silently miss a week (tick catch-up on an always-on host).
3. Due/P0 items visible in ONE pull-based starting-point view with zero navigation (unified dashboard; digest + SessionStart brief dropped 2026-07-09).
4. Capturing a task costs one command or one sentence to Claude.
