Menu
akurai-tasks
publicLatest change 2c9c32aa6fc1bd2551a09c6a1fc1e71b2dd98c79 - feat: complete and deploy AkurAI Tasks by Ólafur Búi Ólafsson
# AkurAI-Tasks — architecture and delivery plan
**Status:** local vertical slice implemented; production hardening, import, and cutover pending
**Date:** 2026-07-14
**Repository:** `olibuijr/AkurAI-Tasks` (private)
**Runtime host:** Titan only
**Design mode:** Ponytail/full — smallest system that can become the single source of truth
without losing data or weakening workflow gates
## 1. Decision summary
Build one AkurAI-Framework-based Rust service that owns projects, workflows, work items,
relationships, comments, evidence, handoffs, execution leases, and immutable audit events.
Expose one domain command layer through:
1. `akurai-tasks` CLI for operators, migration, automation, and deterministic tests;
2. REST for the no-build web interface and integrations;
3. MCP over stdio and Streamable HTTP for agent tool access;
4. a small Framework web interface for humans.
Do **not** implement an ACP task server. ACP is the editor-to-agent protocol; an ACP agent
session receives AkurAI-Tasks as an MCP server. Do not implement A2A initially either. A2A
becomes useful only if AkurAI-Tasks later delegates work to autonomous remote agents; it is
not required to store or coordinate tasks.
Use one process and one embedded AkurAI-Framework BTree database. Keep a current-state
projection and an append-only audit log, but update both in the same BTree commit. This gives
recovery and auditability without the operational cost of Kafka, PostgreSQL, Redis, Temporal,
or a full event-sourcing framework.
## 2. Product definition
AkurAI-Tasks is the authoritative project-management memory for AkurAI work. Hindsight
remains authoritative for durable conversational memory. AkurAI Notes remains authoritative
for user-managed documentation. PassVault remains authoritative for secrets. AkurAI-Tasks
owns only actionable work and its execution history.
```mermaid
flowchart LR
Humans[Human web UI] --> Core[Task command core]
CLI[akurai-tasks CLI] --> Core
MCP[MCP clients and agents] --> Core
REST[REST integrations] --> Core
Core --> DB[(AkurAI BTree)]
Core --> Events[Atomic audit events]
Import[Lossless import bundles] --> Core
Core -. note links .-> Notes[AkurAI Notes]
Core -. credential references .-> Vault[PassVault]
Core -. build evidence links .-> Build[AkurAI Build]
```
### Goal
Move every live project board and database-backed Kanban in `~/Projects` into one service,
then update agents and humans to use that service rather than repository-local files or
private databases.
### Success conditions
- A read-only discovery manifest accounts for every `.kanban`, candidate Kanban database,
runtime/config reference, and gateway authority under `~/Projects`. Every entry has an
evidence-backed `live`, `snapshot`, `dev`, `empty`, `excluded`, or `unresolved`
disposition; unresolved authority blocks migration and cutover.
- Every source entity has exactly one durable disposition: imported, byte-identical
deduplicated, or quarantined with a named diagnostic. Nothing disappears through overwrite,
aggregate counts, or coercion.
- The destination preserves source identity, exact non-secret source bytes, original
status/priority, timestamps with their precision, comments, evidence, handoffs, attempts,
and events where they exist. Credential-shaped source records remain accounted for by
identity/length/digest without copying the suspected value.
- All write interfaces enforce the same scoped authorization, workflow, ownership,
dependency, WIP, evidence, approval, concurrency, revision, and idempotency rules.
- An agent can request a bounded project or epic context bundle, get the ready execution
frontier, claim a leaf item, mutate it idempotently, attach evidence, hand it off, and
complete it without using the web UI.
- Humans can inspect and operate the same records without bypassing gates.
- Final cutover keeps old and new writers fenced until import verification is accepted.
After acceptance, rollback means recovery of AkurAI-Tasks from its event/backup boundary,
never silently reactivating a stale source board.
### Non-goals for the first production release
- Jira marketplace/plugin compatibility;
- JQL or a new query language;
- arbitrary workflow scripting or a visual workflow designer;
- semantic/vector search over tasks;
- Gantt charts, portfolio forecasting, billing, time sheets, or resource accounting;
- chat, email, mobile push, or notification fan-out;
- executing coding agents inside the task server;
- replacing GitHub, AkurAI Build, AkurAI Notes, Hindsight, PassVault, or an agent runtime;
- multi-region replication, Kafka, Redis, PostgreSQL, or microservices;
- automatic destructive cleanup of imported source boards.
These are deferred because none is required to centralize current work safely.
## 3. What Kanban and agile mean here
Kanban is not a drag-and-drop board. It is an explicit pull system:
- a declared commitment point and finish point;
- ordered states with allowed transitions;
- per-state WIP limits;
- dependency-aware pull selection;
- blocked work remains visible and consumes WIP;
- work-item age, cycle time, throughput, and service-level expectation measurements;
- explicit entry/exit policies and current evidence.
The default software-delivery workflow preserves the existing project board contract:
`Inbox → Triage → Discovery → Ready → In Progress → Review → Verification → Release Ready → Done`
Default commitment is `In Progress`; default finish is `Done`; the provisional SLE is 85%
within 10 calendar days, recalculated after 30 completed items. Projects can import different
workflows without pretending that unlike states are equivalent.
Scrum concepts are optional views on the same work:
- a cycle/sprint selects work items for a time box;
- backlog ordering remains project-owned;
- velocity is observed, never used as a quality gate;
- Kanban pull/WIP rules remain valid inside or outside a sprint.
## 4. Agent-first invariants
A million-token context window changes how much an agent can understand in one session. It
does not make chat memory durable, remove retries, prevent two agents from claiming the same
work, or make partial writes safe. Large context is treated as throughput capacity, not as the
database.
1. **Server truth:** client prompts, transcripts, and local files are not task truth after
cutover.
2. **One mutation path:** CLI, MCP, REST, and web call the same typed command handlers.
3. **Atomic state plus event:** each accepted mutation writes the new projection and one
immutable audit event in the same database commit.
4. **Idempotency:** every mutation accepts an idempotency key scoped to principal and command.
The request hash and canonical result commit atomically with the mutation and event.
Repeated delivery returns that result; after result-body expiry, a permanent key/hash
tombstone rejects reuse rather than re-executing the command.
5. **Optimistic revision:** mutable records carry a revision. Stale writes fail with the
current revision and a compact conflict summary.
6. **Fenced execution:** each claim returns an opaque lease token and monotonically increasing
generation. Every ownership-dependent mutation presents both; expiry, release, or reclaim
advances the generation so a stale process cannot act even through the same principal.
7. **Stable assignment:** human, agent, and service identities are principals. Display names
are not keys.
8. **One owner, many observers:** one accountable owner; optional reviewers/watchers do not
create ambiguous ownership.
9. **Leaf execution:** agents execute leaf items. Epics and initiatives are coordination and
roll-up records, so claiming an epic never locks every descendant.
10. **Ready frontier:** the server computes dependency-free, policy-valid, WIP-valid leaf work.
11. **Explicit handoff:** ownership transfers only when the receiver accepts a durable handoff;
the sender remains responsible until then.
12. **Evidence is typed:** implementation, review, verification, release, and resolution
evidence are records, not magic text parsing.
13. **No self-approval by accident:** workflow policies may require a different principal or
role for review, security, verification, or release.
14. **Source fidelity:** normalized fields never replace raw imported fields.
15. **Bounded retrieval:** list/search/context commands are paginated and accept byte/item
budgets even when the client supports one million tokens.
16. **Bulk with locked revalidation:** a batch plan is neither authorization nor current
validation. Apply acquires the write mutex, checks every expected revision, re-evaluates
all commands against one snapshot plus earlier commands in the batch, and commits all or
none. Execution updates remain per-item unless the caller explicitly requests that atomic
batch.
17. **External-effects gate:** merge, deploy, publish, migration, deletion, and secret changes
require an explicit approval policy and named actor.
18. **No secret ingestion:** a pre-serialization scan blocks credential-shaped source records.
The bundle stores only source identity/path, byte length, digest, and a named diagnostic;
it never copies the suspected value or retrieves PassVault values.
## 5. Architecture
### 5.1 Workspace shape
Follow the working AkurAI Notes/PassVault convention rather than inventing a service layout:
```text
Cargo.toml
crates/
tasks-core/ domain records, commands, policies, storage, import bundle
tasks-api/ REST, OIDC/session auth, Framework UI/static serving
tasks-mcp/ MCP protocol and tool/resource/prompt registry
tasks-cli/ one `akurai-tasks` binary and local/remote command adapter
frontend/ native ES modules; no Node build
scripts/ executable gates added only with the capability they test
tests/fixtures/ sanitized import fixtures only
```
The release artifact is one statically linked `akurai-tasks` service binary. Only
`akurai-tasks serve` opens the production BTree; API, web, REST, and remote MCP share that one
database handle. CLI and stdio MCP are stateless adapters to authenticated loopback HTTP or a
Unix socket and never open the production database. Direct database access is allowed only
while the service is stopped or in an explicit exclusive maintenance mode.
### 5.2 Framework reuse
Use sibling AkurAI-Framework crates already used by AkurAI Notes:
- `akurai-http`, `akurai-router` for HTTP;
- `akurai-json` for wire/storage values;
- `akurai-storage` for the BTree database;
- `akurai-schema` for validation primitives;
- `akurai-template`, `akurai-markdown`, `akurai-i18n` for the UI;
- `akurai-vector` is **not** needed in the first release.
Before Increment 1, make two minimal Framework changes upstream: a keyset BTree range API that
stops at caller-supplied item and byte budgets, and a test-only storage fault seam covering
page writes and both commit syncs. Production still uses the concrete BTree; do not add a
repository abstraction. AkurAI Build checks out an exact Framework commit recorded in its
manifest/Cargo lock into a deterministic workspace path before Cargo runs, so releases never
depend on an ambient sibling checkout.
The generated `backend/collections.toml` example is not the task schema. Generic CRUD cannot
enforce workflow, event, revision, lease, or idempotency invariants.
### 5.3 Storage model
Use prefixed BTree records and secondary indexes. Representative prefixes:
```text
meta/*
workspace/<id>
project/<id>
workflow/<id>
state/<workflow>/<id>
principal/<id>
role-binding/<principal>/<scope>/<role>
credential/<id>
session/<hash>
item/<id>
item-key/<project>/<sequence>
edge/<from>/<kind>/<to>
comment/<item>/<sequence>
evidence/<item>/<sequence>
handoff/<item>/<sequence>
lease/<item>
event/<global-sequence>
event-by-project/<project>/<project-sequence>
event-by-item/<item>/<global-sequence>
source/<id>
source-identity/<source>/<escaped-identity>
source-ref/<source>/<escaped-source-key>
archive-entity/<source>/<entity>
import-run/<id>
import-disposition/<run>/<source-entity>
import-raw/<run>/<source-entity>
idempotency/<principal>/<key>
```
A process-wide database mutex serializes writes. One command may update several keys, then one
`BTree::commit()` atomically advances the durable root. All keys/values are constructed and
serialized before the first tree write. Any insert, delete, or commit error poisons the live
handle: readiness drops, writes stop, and the service drops/reopens the BTree under the mutex,
checks the durable meta root, and resumes only if integrity passes. The caller retries the same
idempotency key to resolve an ambiguous commit. Reads use range prefixes and opaque scoped
cursors. The first release does not add a second database, cache, or message broker.
### 5.4 Core records
| Record | Purpose | Required fields |
|---|---|---|
| Workspace | Security/administrative boundary | id, key, name |
| Project | Repository/product boundary | id, key, name, repo, workflow, archived |
| Principal | Human, agent, service, or non-authenticating import identity | id, kind, issuer/subject or source, display name, active |
| Role binding | Additive default-deny authorization scope | principal, workspace/project scope, role, revision, grantedBy, createdAt |
| Credential | Hashed service authentication | id, principal, token hash, created, expires, revoked, revision |
| Session | Hashed browser session | hash, principal, created, expires, revoked |
| Workflow | Project flow definition | states, transitions, commitment, finish, SLE |
| State | Ordered Kanban state | id, name, category, position, WIP, entry/exit policy |
| Work item | Initiative/epic/story/task/bug/etc. | id, project, key, type, title, body, state, optional owner, revision |
| Edge | Typed graph relation | from, to, kind (`parent`, `blocks`, `relates`, `duplicates`, `supersedes`) |
| Cycle | Optional sprint/time box | project, name, start, end, status |
| Comment | Human/agent narrative | item, actor, body, createdAt |
| Evidence | Gate evidence | item, stage, actor, result, artifact refs, createdAt, source revision |
| Handoff | Durable ownership transfer | item, from, to, state, structured sections, acceptedAt |
| Lease | Exclusive active execution | item, principal, token hash, generation, acquired, expires, heartbeat |
| Event | Immutable audit | internal sequence, scoped sequence, command, actor, item/project, before/after revision, payload |
| Source | Import/sync instance | kind, location, role, capabilities, watermark, raw config digest |
| Source identity | Non-authenticating imported label | source, raw label, optional explicitly mapped principal |
| Archive entity | Read-only snapshot history | source, source key/path, lineage link, normalized fields, raw ref |
| Import run | Dry-run/apply/verify result | source, plan digest, mode, counts, diagnostics, digest, createdAt |
| Import disposition | One source entity outcome | source identity, outcome, destination/archive/raw refs or diagnostic |
| Import raw | Immutable exact non-secret source bytes | run, source entity, base64 bytes, length, digest |
| Idempotency | Atomic retry result/tombstone | principal, key, request hash, canonical result or tombstone |
Large attachments are external artifact URIs with digest/media metadata. The first release does
not put arbitrary blobs in the task database.
### 5.5 Work hierarchy and planning
- Default types: initiative, epic, story, task, bug, security, performance, docs, chore, spike.
- Type is configurable per project, but hierarchy is one `parent` edge; no separate epic table.
- A child belongs to at most one parent. Cycles are rejected.
- Epics/initiatives show derived child counts, state distribution, ready frontier, blockers,
and completion percentage.
- An epic cannot close until it has at least one child, all required descendants are resolved,
and its own acceptance criteria have resolution evidence.
- A large-context agent requests `epic_context`, then repeatedly pulls ready leaves. The
context can stay open while durable state advances through MCP calls.
- `owner` is optional before the workflow commitment point. The transition into commitment
requires an accountable active principal, and `claim` atomically assigns an unowned item
while creating its lease. Imported assignee labels remain non-authenticating Source
identities until an administrator explicitly maps them.
### 5.6 Workflow command transaction
Every mutation follows this order while holding the database write mutex:
1. authenticate the principal and load scoped role bindings;
2. resolve the idempotency key and request hash, replaying an existing committed result or
rejecting a mismatched/reused tombstone;
3. load records and compare expected revisions;
4. validate default-deny command permission, ownership, current lease token/generation,
separation of duty, transition graph, dependencies, blocker, WIP, and gates;
5. construct and serialize the changed projection, indexes, typed
evidence/handoff/comment records, audit event, and canonical idempotency result before the
first tree write;
6. write every projection, index, event, and idempotency key/result;
7. commit once and return the already-committed result;
8. on any tree-write/commit error, poison and reopen the handle as defined in §5.3;
9. emit a best-effort SSE/WebSocket notification after commit.
`batch apply` repeats steps 1-4 for every planned command against one locked current snapshot
plus earlier commands in the batch. A plan digest never bypasses authorization or revalidation.
Any failure writes nothing.
Notification delivery is not transaction truth. Clients recover through opaque authorized
cursors, never a raw global sequence.
## 6. Interfaces
### 6.1 CLI first
The CLI is the reference interface and always offers `--json`. Human text is a rendering of
the same response, not a separate implementation.
```text
akurai-tasks serve
akurai-tasks mcp stdio --socket PATH --credential-ref REF
akurai-tasks doctor
akurai-tasks backup --output PATH
akurai-tasks maintenance doctor|backup|restore
akurai-tasks auth bootstrap --subject SUBJECT --confirm SUBJECT
akurai-tasks auth principal disable
akurai-tasks auth credential issue|rotate|revoke
akurai-tasks auth binding grant|revoke
akurai-tasks project list|show|create|archive
akurai-tasks workflow show|validate
akurai-tasks work create|show|list|update|transition|block|unblock
akurai-tasks work next|claim|renew|release
akurai-tasks work comment|evidence|handoff|accept
akurai-tasks work context --project KEY|--root KEY --detail compact|full
akurai-tasks batch plan|apply
akurai-tasks import discover|scan|plan|apply|verify
akurai-tasks events tail --after CURSOR
akurai-tasks metrics project KEY
```
Destructive commands require an explicit target, expected revision, and `--confirm <target>`;
no interactive terminal prompt is required for agent operation.
### 6.2 REST
Version the domain API at `/api/v1`. Core resources:
- `/health`, `/ready`;
- `/projects`, `/projects/{id}/workflow`, `/projects/{id}/metrics`;
- `/work-items`, `/work-items/{id}`, `/work-items/{id}/context`;
- command endpoints under `/work-items/{id}/commands/{transition|claim|renew|block|...}`;
- `/batch/plan`, `/batch/apply`;
- scoped `/events?after=` and `/events/stream` with opaque authorization-bound cursors;
- `/imports`, `/imports/{id}/diagnostics`, `/imports/{id}/archive`;
- `/principals/me`, administrator-only `/principals`, `/credentials`, and `/role-bindings`.
Mutations carry `Idempotency-Key` and `If-Match`/expected revision. List endpoints use cursor
pagination; no fixed 200-row export cap.
Event cursors bind principal, authorized scope set, filters, and direction. The internal global
sequence is available only to global-audit administrators; project callers receive project
sequences and opaque cursors whose shape does not reveal interleaved activity. A changed role
set invalidates the cursor and requires a fresh query.
### 6.3 MCP
Implement the official 2025-11-25 baseline with JSON-RPC and authenticated Streamable HTTP at
`/mcp`. Validate `Origin`, bind local development to loopback, require authentication, and
negotiate protocol versions. A stdio mode is only a stateless MCP-to-loopback/Unix-socket
adapter bound to a configured scoped service principal; it keeps stdout MCP-clean and never
opens the BTree.
The stdio command resolves the PassVault reference outside stdout, connects to the configured
socket/loopback endpoint, writes protocol messages only to stdout, sends diagnostics to stderr,
and exits non-zero if authentication or the service connection fails. CLI flags override
environment, which overrides the non-secret config file; raw tokens are never accepted as CLI
arguments.
Keep the tool surface small and composable:
| Tool | Contract |
|---|---|
| `projects_list` | scoped projects and workflow summaries |
| `work_get` | one work item with selected relations/history |
| `work_query` | structured filters, cursor, fields, budget |
| `work_next` | dependency/WIP/policy-valid execution frontier |
| `work_create` | one item with source/idempotency metadata |
| `work_batch_create` | atomic validated planning batch |
| `work_update` | revision plus current lease token/generation when ownership-protected |
| `work_transition` | policy/revision/lease-fenced state transition |
| `work_claim` | acquire token plus a new lease generation; only its hash is stored |
| `work_renew` | renew the presented caller-owned generation |
| `work_block` / `work_unblock` | explicit blocker lifecycle |
| `work_comment` | append narrative comment; lease fence when owner-only |
| `work_evidence` | append typed gate evidence with applicable lease fence |
| `work_handoff` / `work_accept_handoff` | durable fenced ownership transfer |
| `work_context` | bounded project/epic context bundle |
| `events_read` | audit events after cursor |
| `metrics_get` | flow metrics and SLE |
| `import_status` | read migration/diagnostic status; no remote import apply by default |
MCP resources expose read-only project/workflow schemas and canonical work-item URIs. MCP
prompts provide `triage`, `plan_epic`, `resume_work`, and `review_work` templates. Tool
responses return compact structured data plus `next_actions`; they do not dump an entire
workspace unless the caller asks for a full context bundle with an explicit budget.
### 6.4 ACP and A2A
- **ACP:** no AkurAI-Tasks ACP implementation. ACP launches/connects an agent; its
`session/new` configuration supplies the AkurAI-Tasks MCP server. Document client snippets
after the MCP endpoint is live.
- **A2A:** deferred adapter. Add only when a remote agent must accept delegated tasks as an
agent rather than call task tools. A2A task IDs, messages, and artifacts would link to
AkurAI work items; they would not become the storage schema.
- **Webhooks:** later than the audit event stream. GitHub/AkurAI Build connectors consume or
publish events through maintained adapters.
### 6.5 Human web interface
Framework-native HTML/CSS/ES modules, no React, npm, bundler, or design-system dependency.
Preserve the established AkurAI-Framework dark utility theme, its current tokens, typography,
spacing rhythm, focus treatment, and Forkbird identity rather than creating a second visual
system. The Framework Forkbird becomes a full-width branded hero, not an ornamental card.
First useful UI:
1. project switcher and cross-project inbox;
2. backlog/board view with WIP and blocked visibility;
3. item detail with hierarchy, links, comments, evidence, handoff, lease, and audit;
4. epic tree/dependency view;
5. agents/leases view;
6. imports and diagnostics view;
7. workflow/metrics read-only administration.
Drag-and-drop may request a transition but never bypasses server policy. Success/failure uses
bottom-right accessible toasts. Deletion/archive/force actions use a styled in-app confirmation
dialog with the exact consequence and safe Cancel default; never native browser dialogs. The UI
gate uses the UI/UX Pro Max brief, Taste direction, and Impeccable audit at 375 px, 768 px, and
desktop while keeping the existing theme.
## 7. Identity, authorization, and secrets
- Human UI: AkurAI IDP OIDC issuer plus subject maps exactly to one human principal.
- OIDC uses state verification, nonce and PKCE where supported by the IDP. Browser sessions
are server-side hashed, expiring, revocable records; cookies are `Secure`, `HttpOnly`, and
`SameSite=Lax`, and cookie-authenticated mutations require CSRF tokens.
- Remote MCP/API and local stdio use one-time-issued random service credentials. Store only a
slow hash plus principal/created/expiry/revoked metadata server-side and place the returned
value directly into a PassVault entry; it is never displayed again. Rotation issues a new
credential before explicitly revoking the old one.
- Inactive principals, expired/revoked credentials, and revoked sessions fail before
authorization. Local stdio maps the presented credential to its server-side principal and
cannot assert another subject.
- Durable additive role bindings grant viewer, contributor, planner, implementer, reviewer,
verifier, releaser, or administrator at workspace/project scope.
- Authorization is default-deny. Workspace grants cascade into its projects; project grants
add permissions only in that project. Revocation removes exactly one
principal/scope/role binding. No negative binding or policy DSL exists.
- Reads, event cursors, context bundles, imports, project administration, and mutations filter
by role and project scope; ownership/lease and review/release separation remain additional
predicates. Administrator is not an implicit bypass for leases, evidence, or separation.
- Connector configuration stores a PassVault entry reference only. PassVault folder
`AkurAI-Tasks` (ID 5) holds actual values.
- Task data, Notes, Hindsight, logs, imports, and repo configuration never contain credentials.
- Audit events record role/credential-reference metadata changes, never secret values.
### 7.1 Empty-store authorization bootstrap
The empty store has one auditable bootstrap ceremony. With the service drained, a local
maintenance-socket command binds an exact OIDC subject or PassVault-referenced service
principal, then atomically creates that Principal, the workspace administrator Role binding,
an immutable event, and `meta/bootstrap-complete`. It requires exact `--confirm`, accepts no
raw credential value, and refuses if the marker or any role binding exists. Concurrent or
replayed bootstrap attempts produce one winner and no partial records.
After bootstrap, only authorized administrators can grant/revoke bindings through normal
commands. They cannot remove the final active workspace administrator without first granting a
replacement; every grant/revoke uses expected revision, idempotency, separation policy, and an
audit event.
### 7.2 Static permission matrix
Roles compose additively. This fixed table is reviewed data in `tasks-core`, not a configurable
authorization language:
| Command family | Required role |
|---|---|
| project/workflow/item/archive/import-status/event/context/metrics read | viewer or any stronger functional role |
| comment on visible work | contributor |
| create/update backlog, links, cycles, batch plan/apply | planner |
| ready frontier, claim/renew/release, owner-scoped update/block/evidence/handoff/transition | implementer |
| review evidence and review transitions | reviewer |
| verification evidence and verification transitions | verifier |
| release approval and configured external-effect execution | releaser |
| workspace/project/workflow administration, import apply, principal/credential/binding administration | administrator |
“Stronger” means any listed non-viewer role gains viewer reads; functional roles do not inherit
from each other. Project archive, import apply, and credential/binding changes are administrator
commands with explicit target confirmation. The first release has no generic break-glass bypass;
administration never bypasses workflow, lease, evidence, or separation gates. Tests cover one
allow and deny per family through CLI, REST, and MCP where that family is exposed.
## 8. Source inventory and migration
### 8.0 Discovery and authority gate
`akurai-tasks import discover ~/Projects` performs a read-only exhaustive scan and emits a
versioned source manifest. It records every `.kanban`, candidate Kanban SQLite store,
runtime/config reference, and gateway authority with evidence-backed `live`, `snapshot`,
`dev`, `empty`, `excluded`, or `unresolved` disposition. It does not read secret values.
Unresolved authority blocks `import plan`, `apply`, and cutover. Discovery must prove the
running BunFast database path through a maintained status/export interface and recover the
exact RustAgent authority. Rerun discovery immediately after each writer fence so a source
created or moved during implementation cannot be silently missed.
### 8.1 File boards found on Titan
Exactly 19 `.kanban` directories were inventoried:
- 16 empty modern schema-v1 copies: AkurAI-VPN, titan-s3, hindsight-memory, osx-theme,
kde-template-notetaker, kde-template-files, dotnet-test-1, carryset, bunfast, pi-bun,
AkurAI-PassVault, AkurAI-Notes, AkurAI-IDP, AkurAI-Framework, AkurAI-Builds, AkurAI-Build;
- live `bunfork/.kanban`: 6 cards and 38 JSONL events;
- `github-workflow-audit/bunfork/.kanban`: divergent epic-enabled audit snapshot with 123
cards and about 165 KB of events;
- legacy `tv-kit/.kanban`: 32 YAML-frontmatter active task files, no event log, and a real
duplicate ID (`TASK-010` in two distinct files).
The 17 baseline modern boards use nine states, JSON frontmatter cards, dependencies, typed
evidence, handoffs, decisions, WIP, SLE, and append-only JSONL events. Capability detection,
not `schemaVersion` alone, distinguishes the epic-aware audit variant.
### 8.2 BunFast database
BunFast is the locally source-complete DB-backed board. Its default authoritative candidate is
`~/Projects/bunfast/data/bunfast.sqlite`; exact live override remains unproven because secret
environment content was correctly not read. Resolving the running service's actual database
path through a maintained metadata/status command is a hard blocker for plan, apply, and
cutover. Current default-DB metadata counts are:
| Entity | Count |
|---|---:|
| projects | 4 |
| columns | 28 |
| tasks | 38 |
| comments | 266 |
| task runs | 0 |
| worker approvals | 0 |
| handoff dispatches | 161 |
| agent dispatch leases | 0 |
| dynamic components | 1 |
A separate `bunfast.dev.sqlite` has 2 projects, 11 columns, and 1 task; treat it as a dev
fixture unless runtime configuration proves otherwise. Use BunFast's maintained
`deploy.sh backup` SQLite `.backup` plus integrity check. Never copy a WAL-backed main file
alone. Export projects, columns, tasks, comments, runs, approvals, handoff dispatches,
relevant settings and component links. Exclude transient dispatch leases; rebuild FTS.
### 8.3 AkurAI-IDP / RustAgent gateway
AkurAI-IDP is only an authenticated proxy. It exposes four-state Kanban operations and
claim/heartbeat/reclaim/dispatch calls to `127.0.0.1:8644`, but the authoritative
`AkurAI-RustAgent` checkout/database is absent from Titan. This is a migration blocker, not
permission to guess its schema or scrape the UI. Acquire the exact deployed gateway source
and store, inventory it, drain/understand claims, and export from that authority before final
"all projects" cutover.
### 8.4 Import bundle
All source adapters emit a canonical, versioned JSONL `ImportBundle v1`:
- manifest: source kind/location/role/capabilities/config digest/watermark;
- projects/workflows/states;
- principals as non-authenticating Source identities pending explicit mapping;
- active items with normalized candidates plus adapter-specific exact non-secret source bytes;
- edges, checklist entries, comments, evidence, handoffs, attempts, decisions, and events;
- a sorted disposition candidate for every source entity with source kind/key/path, byte
length, digest, intended outcome, destination ID candidate, or diagnostic.
Before serialization, adapters scan each record for credential-shaped material. A match emits
only identity/path, byte length, digest, and a blocked diagnostic, never the matched bytes. The
source stays untouched and apply remains blocked until remediation through the approved secret
process.
The exact-byte boundary is the whole file for file boards and each canonical byte record from
the maintained BunFast/RustAgent snapshot exporter for databases. Capture bytes before parsing
and carry them as base64 in the bundle for the measured source sizes. `import apply` persists
each non-secret entity under immutable `import-raw/<run>/<entity>` keys in the same commit and
stores that raw reference on its disposition/archive entity; normalized fields remain separate.
Verification decodes the destination record and recomputes length/digest without consulting
the source. This preserves whitespace, newline form, key order, malformed bytes, and unknown
fields. Credential-shaped entities are the only deliberate no-byte exception.
Adapters:
1. modern file-board reader;
2. legacy tv-kit YAML/frontmatter reader;
3. BunFast snapshot exporter/reader;
4. RustAgent adapter only after its authority is recovered.
Adapters do not mutate sources. `import plan` validates and produces a canonical cryptographic
digest covering counts, mappings, collisions, orphans, precision loss, and the per-entity
disposition set; no signing key or signature scheme exists. For the inventoried source sizes,
one source `import apply` plus its completed Import run, raw records, archive entities, and all
dispositions is one BTree transaction and is invisible before commit. A retry replays the same
committed run/result. Chunking is deferred until a measured transaction-size ceiling requires
a checkpoint protocol. `import verify` proves a one-to-one partition of the source
inventory into imported, byte-identical-deduplicated, or quarantined outcomes and fails on
omissions, duplicate outcomes, or extra destination source refs.
### 8.5 Collision and precedence policy
- Destination identity is internal ID plus unique `(source_instance, source_key/source_path)`;
bare `TASK-010` or `KB-*` is never globally unique.
- Import both tv-kit `TASK-010` files as separate internal items and emit a duplicate-source-ID
diagnostic. Never merge or overwrite them.
- Treat live `~/Projects/bunfork` as current. Its six live records become active Work items.
Treat `github-workflow-audit/bunfork` as an audit snapshot: its 123 cards become immutable
Archive entities linked by explicit source-key/byte lineage where possible, never ordinary
Work items. Archive entities are inspectable only through explicit import/archive queries
and are excluded by construction from boards, ready frontier, WIP, cycles, metrics, claims,
transitions, and ordinary context. Conflicts remain separate with source attribution.
- Empty boards create project/workflow records, not fake README tasks.
- Preserve physical column/path and metadata status separately and diagnose disagreement.
- Preserve legacy date precision and raw priorities/statuses. Mapping never erases originals.
- Do not synthesize events when a source has none.
- AkurAI Build runs/jobs become external evidence links, not Kanban cards.
### 8.6 Cutover sequence
For each source, independently:
1. run exhaustive discovery and resolve every authority disposition;
2. register the source, obtain a consistent snapshot/backup, and record digest/watermark;
3. plan import and resolve or explicitly quarantine every diagnostic;
4. apply idempotently into a staging workspace;
5. verify per-entity dispositions, counts, relations, raw digests, state distributions,
comments, events, and sampled full records;
6. rehearse deletion of only the staging import namespace and restore of AkurAI-Tasks;
7. ensure the hardened central service, scoped auth, backup/restore, and rollback rehearsal
have passed before any live source is fenced;
8. promote every discovered writer authority/capability into the cutover manifest covered by
its canonical audited digest and install its maintained hard fence: revoke/stop database
writers or make every file-board mutation path fail, then rerun discovery and record the
fence/config digest;
9. keep AkurAI-Tasks external writers fenced, run final atomic import and verification, update
project clients/instructions, and prove every listed old-source write path rejects writes
while reads remain available;
10. restart/redeploy each source through its normal maintained path, repeat every writer-fence
probe, explicitly accept cutover, enable AkurAI-Tasks writes, and retain the old source
read-only until the recovery retention gate permits a separate archive/deletion decision.
Old and new writers are never enabled simultaneously during final cutover. Before acceptance,
rollback removes the unaccepted destination namespace while both sides remain fenced. After
acceptance, rollback means restoring/replaying AkurAI-Tasks without reactivating the stale
source. No bulk deletion or blind rewrite of `.kanban` directories occurs. Cutover completes
only when every discovered source has an accepted verify report and no authority is unresolved.
## 9. Jira parity, deliberately scoped
| Capability | First production release | Later only when needed |
|---|---|---|
| Projects, work types, hierarchy | Yes | portfolio cross-project hierarchy |
| Configurable workflows/states/transitions | Import + validated config | visual designer / scripting |
| Kanban/backlog/WIP/blocking | Yes | advanced swimlanes |
| Dependencies and typed links | Yes | critical-path forecasting |
| Assignment, leases, handoffs | Yes | skills-based auto-routing |
| Comments, evidence, audit | Yes | rich collaborative editing |
| Sprints/cycles | Minimal optional model | velocity/capacity forecasting |
| Custom fields | Typed project definitions after core | marketplace field types |
| Search/filter | Structured filters + text contains | JQL compatibility / semantic search |
| Reports | WIP, age, cycle time, throughput, SLE | executive portfolio analytics |
| Attachments | external artifact links | managed upload UI |
| Permissions | project roles/scopes | enterprise policy designer |
| Automation | explicit transitions/connectors | general no-code automation engine |
| GitHub/AkurAI Build | links and evidence adapters | bidirectional project sync |
| Import | all current AkurAI sources | Jira/Plane/Linear importers |
## 10. Testing and validation contract
Add each executable gate only when its capability exists; never add a green placeholder.
### `scripts/check.sh`
Single local quality gate:
1. `cargo fmt --all --check`;
2. `cargo clippy --workspace --all-targets -- -D warnings`;
3. `cargo test --workspace`;
4. release build for the supported target;
5. frontend static/reference checks;
6. secret-pattern and generated-artifact policy checks;
7. MCP schema snapshot compatibility check;
8. import fixture schema check after ImportBundle lands.
### `scripts/test-import.sh`
Creates temporary destination databases inside the repository test area and runs sanitized
fixtures for:
- empty modern board;
- populated modern board and JSONL history;
- epic-aware modern variant;
- tv-kit duplicate IDs and day-precision dates;
- BunFast projects/columns/tasks/comments/handoffs;
- interrupted source file move/event mismatch;
- destination apply failpoint before commit leaves zero keys;
- tree failpoints after every key write and both commit syncs prove that reopen exposes only the
complete old or new root and that same-key retry resolves ambiguous commit;
- destination apply failpoint after commit replays the identical run/result;
- idempotent re-import and a stale batch-plan revision/WIP change that writes nothing;
- conflicting live/snapshot lineage;
- malformed/orphan records and one credential-shaped record quarantined without copying the
matched bytes;
- exact non-secret source bytes survive decode/re-hash, and every entity has exactly one
disposition.
It must prove the source fixtures are unchanged and clean up its databases.
### `scripts/validate.sh --local|--live`
- process/systemd status where applicable;
- loopback and public `/health` plus `/ready` schemas;
- authenticated scoped REST read, denied unauthenticated mutation, and denied cross-project ID
access;
- interleaved multi-project events expose no global-sequence gap or cross-project timing
side-channel, and role changes invalidate scoped cursors;
- MCP initialize, tools/list, one read-only tool call, Origin rejection, and stdio adapter proof
that only the serving process owns the database;
- MCP initialize capability advertisement exactly matches registered dispatch handlers;
`resources/list` plus `resources/read` and `prompts/list` plus `prompts/get` each succeed;
- CLI `doctor`, offline maintenance restore from an unstartable database, and event cursor read;
- database integrity/salvage check and backup restore smoke;
- bootstrap replay/concurrency rejection;
- service credential issue/use/revoke/expire, inactive-principal rejection, exact OIDC
issuer/subject plus state validation, session revocation, and CSRF rejection;
- create → claim → evidence → handoff → accept → transition happy path in an isolated
validation project;
- two sessions sharing one principal prove stale lease token/generation rejection after
expiry/reclaim, including external-effect boundaries;
- stale revision, duplicate/late idempotency, dependency, WIP, self-review, release-approval,
privileged-command, and stale batch-plan rejection paths;
- web shell and accessible toast/dialog smoke.
### Behavioral test matrix
Tests defend observable contracts: atomic projection/event, poisoned-handle recovery,
idempotent retries, revision conflicts, bootstrap uniqueness, authentication/session lifecycle,
static permission-family conformance, no duplicate live leases, lease token/generation fencing
after restart/reclaim, dependency cycles, WIP, workflow gate evidence, handoff ownership, role
separation, opaque cursor isolation, exact-byte source preservation, active/archive projection,
source collision preservation, pagination, authorization scope, and backup/restore. Source-text
tests do not count.
## 11. Deployment and operations
### Topology
- Build and run on Titan only.
- One hardened systemd service, one binary, one data directory, one mode-0600 environment
file, one Framework frontend directory.
- Bind the application to loopback or the approved AkurAI VPN service address. TLS terminates
at the maintained edge. Do not expose an unauthenticated LAN REST API.
- Allocate the port through the maintained AkurAI deployment tooling; generated `8090` is a
local scaffold default, not a production reservation.
- `serve` and every offline maintenance command hold the same host-level exclusive lock.
Maintenance resolves a configured allowlisted data path to a descriptor, requires the
service to be stopped/drained, stages and verifies restore data, fsyncs file and parent
directory, atomically swaps files, and preserves the replaced database until verification.
- Public candidate: `akurai-tasks.olibuijr.com`, created only through maintained Nginx/TLS
commands after DNS and auth are ready.
### Release path
1. `scripts/check.sh` and import tests;
2. AkurAI Build repository registration and pipeline using a repository `.akurai.yml` added
with executable code, not during planning;
3. static musl release artifact plus checksums;
4. fence external writes and set readiness false;
5. backup the current database and verify integrity;
6. install new binary/assets atomically while preserving env/data;
7. run schema migration under exclusive lock with rollback copy;
8. restart the hardened service while external writes remain drained;
9. run `scripts/validate.sh --live` and backup/restore checks;
10. promote and enable writes only after status is `succeeded`; before promotion, rollback may
restore the binary/database copy because no post-backup external write was accepted.
Deploy, rollback, vhost, TLS, secret provisioning, and service mutations use maintained
AkurAI Build/AkurAI deployment commands from Titan. No manual SSH/systemd/Nginx/database
mutation becomes an undocumented second path.
### Backup and recovery
- Online `akurai-tasks backup` obtains a consistent database snapshot and manifest/digest.
- Offline `maintenance doctor|backup|restore` uses the service lock and works even when
`serve` cannot open the database.
- The first release accepts an RPO of at most one hour; there is no fictional replay after loss
of the only BTree. Verified hourly, pre-release, and pre-cutover generations go to an
encrypted deployment-managed target outside the service data directory and Titan's storage
failure domain. Keep at least 24 hourly, 30 daily, and 12 monthly generations; prune only
after the next generation is verified.
- Every schema version has forward migration plus tested restore/rollback boundary.
- `doctor` checks BTree integrity, index/source-ref consistency, orphaned edges, event
sequence, active leases, and migration state.
- Recovery never reconstructs accepted history from chat transcripts. It restores the newest
verified generation and explicitly reports any interval after that recovery point as lost.
- A restore drill must meet the selected RPO before any source archive may leave read-only
retention.
## 12. Delivery increments
Increments 1-4 are integratable, behaviorally complete vertical increments; no scaffold-only
milestone is called done. Increment 5 is the first production-deployable release.
### Increment 1 — secure command core and one vertical slice
Implement workspace/project/workflow/item/event/idempotency, principal, scoped role-binding,
credential/session, revision, and bootstrap records; minimum static default-deny permission
matrix; administrator binding and credential issue/rotate/revoke; one binary; CLI
create/show/list/transition and stdio MCP adapter; REST equivalents; MCP initialize/tools/list
plus read/create/transition; health/ready; exact OIDC/session/CSRF and service-credential tests;
atomic event/idempotency and poisoned-handle tests; Framework bounded-range/fault-seam
prerequisites; `scripts/check.sh` plus a focused local authenticated three-interface smoke.
Acceptance: bootstrap has exactly one winner, credential revocation is immediate, an authorized
item traverses a test workflow through all three interfaces with identical rule enforcement,
and unauthenticated, cross-project, stale-revision, commit-failure, and repeated-delivery cases
are rejected, recovered, or replayed with an auditable actor/event sequence.
### Increment 2 — coordination safety
Add dependency graph, ready frontier, WIP, blockers, leases, evidence, handoffs, comments,
event cursor/stream, locked batch planning/apply, and context bundles. Acceptance: concurrent
claim/retry/restart, stale-plan, and independent review/release gates pass behavioral tests.
### Increment 3 — lossless import and verification
Add exhaustive discovery, ImportBundle v1, modern file, tv-kit, and BunFast adapters;
dry-run/atomic apply/verify; durable exact-byte retention; non-authenticating source identities;
active-versus-archive projection; per-entity dispositions; diagnostics/quarantine;
online/offline backup/restore; and the real `scripts/test-import.sh`. Acceptance: sanitized
fixtures and real read-only dry runs produce stable authority manifests, counts/digests,
preserve exact non-secret bytes and known collisions, keep all 123 Bunfork snapshot cards
inspectable while only six live cards affect active work, survive failpoints, and are
idempotent. RustAgent remains an explicit unresolved blocker until recovered.
### Increment 4 — human control plane
Add IDP-authenticated project/board/item/epic/import/agent/metrics pages with accessible
feedback and confirmation. Acceptance: browser flow can inspect and perform allowed commands
but cannot bypass gates.
### Increment 5 — production hardening before cutover
Add AkurAI Build pipeline, static artifact, hardened service, scoped auth, independently stored
hourly backups, full `scripts/validate.sh --local|--live`, metrics, exhaustive persistent
source-write fencing controls, and rollback rehearsal. Acceptance: local and public health,
MCP, REST, UI, authorization, unstartable-database restore, source-fence/restart, and rollback
checks pass on the promoted artifact before any old board writer is disabled.
### Increment 6 — source-by-source migration
Migrate the 19 file boards and BunFast after authority resolution and consistent snapshots.
Recover/inventory the missing RustAgent authority and add its adapter. Fence old and new writers,
cut over each project independently, then retain read-only source archives. Acceptance: every
discovered source entity has exactly one accepted disposition, no authority is unresolved,
every inventoried legacy writer rejects before and after normal restart/redeploy, and no live
writer uses an old board.
## 13. Risks and controls
| Risk | Control |
|---|---|
| Central service becomes a single point of failure | poisoned-handle recovery, exclusive offline maintenance, hourly independent backups, tested restores |
| Bare task IDs collide | internal IDs plus source-instance/source-path uniqueness |
| Import normalization loses truth | exact non-secret source bytes plus original values/digests retained; diagnostics instead of coercion |
| Audit snapshot overwrites live Bunfork | explicit live/snapshot roles and lineage revisions |
| RustAgent data omitted | cutover blocker until authority is recovered and inventoried |
| Agent retries duplicate mutations | atomic idempotency key/request hash/result plus permanent tombstone |
| Concurrent agents overwrite/claim work | expected revision plus token/generation-fenced expiring lease |
| Long context encourages giant undifferentiated epics | leaf execution frontier and durable per-leaf evidence |
| MCP exposed without transport security | Origin validation, scoped auth, loopback local bind, official transport rules |
| Interface rules diverge | one domain command layer and cross-interface conformance tests |
| Workflow configurability becomes a DSL | data-only states/transitions/policies first; no scripting engine |
| Task server absorbs memory/docs/secrets/builds | explicit ownership boundaries and external references only |
## 14. Adversarial review protocol
Before this planning baseline is committed, run three sequential independent reviews. Each
review receives the current repository plan and the previous review disposition. Required
axes:
1. data-loss and migration correctness;
2. distributed/concurrent agent failure modes;
3. MCP/ACP/A2A protocol boundaries;
4. security, identity, authorization, and secrets;
5. operational simplicity and Ponytail/YAGNI;
6. testability, rollback, and objective acceptance;
7. whether the plan really reaches the user's "all boards in one service" goal.
The requested Opus 4.8/xhigh model is preferred when an execution environment exposes that
selector. This harness does not expose a per-task model selector, so the reviews use the
specialized reviewer agent available here; the model identity must not be fabricated.
Review findings and dispositions:
| Iteration | Initial verdict | Findings | Disposition |
|---|---|---:|---|
| 1 | REVISE | 10 | All accepted: atomic idempotency/result commit, locked batch revalidation, exhaustive authority discovery, per-entity import dispositions, stdio single-writer topology, durable role bindings, hard writer fences, safe secret quarantine, rollback boundaries, and hardening before cutover. |
| 2 | REVISE | 9 | All accepted: one-time auth bootstrap, honest one-hour RPO, poisoned BTree reopen, offline maintenance restore, lease token generations, opaque scoped cursors, exact source bytes, exhaustive restart-stable fences, and staged executable gates. |
| 3 | REVISE | 11 | All accepted: optional pre-commit owner and non-authenticating source identities, credential/session/CSRF contract, static permission matrix, durable import raw records, active/archive projection split, pinned Framework range/fault prerequisites, coherent live gates, explicit stdio command, digest terminology, MCP resource/prompt checks, and Notes wording. |
No finding was rejected or deferred. This document incorporates the third disposition and is
the implementation handoff baseline. Start with the two pinned Framework prerequisites and
Increment 1. Do not write source migrations before Increment 3, expose production before
Increment 5, or fence any legacy writer before Increment 5 passes.
## 15. External references
- MCP specification and transports: <https://modelcontextprotocol.io/specification/2025-11-25>
- MCP Streamable HTTP security/transport contract:
<https://modelcontextprotocol.io/specification/2025-11-25/basic/transports>
- Agent Client Protocol purpose: <https://agentclientprotocol.com/get-started/introduction>
- Linux Foundation A2A scope: <https://a2a-protocol.org/latest/topics/what-is-a2a/>
- Plane's first-party MCP transport/auth/identifier model:
<https://developers.plane.so/dev-tools/mcp-server>
- Jira administration surface: <https://support.atlassian.com/jira-cloud-administration/resources/>
- Beads agent-native dependency graph: <https://github.com/gastownhall/beads>
- Vibe Kanban agent execution/UI reference: <https://github.com/BloopAI/vibe-kanban>
- Database-backed Kanban MCP reference: <https://github.com/multidimensionalcats/kanban-mcp>
- MCP-native agent collaboration reference: <https://github.com/cookjohn/teammcp>
The references inform interface and failure-mode choices. AkurAI-Tasks does not copy their
stacks or expand scope to match their feature counts.