Commit graph

4 commits

Author SHA1 Message Date
Randall Stillwell
6ccb060bea feat(second-brain): open self-hosted Obsidian for crews — harness-agnostic v0.1
- MCP create-backlog-item for natural language Plan/Epic/Task authoring
- Worker non-code: optional worktree + per-harness allowlist + doc_review→published
- Harness registry: harness_providers/role_harness_routes, WorkerAdapter (minimal|crewai|langgraph|remote-ag-ui), AG-UI POST /api/ag-ui, Settings → Harnesses with Test
- Plans tree: backlog.listTree + createPlan/Epic/Task + Start→Convoy, web CRUD without CLI
- Fleet: /fleet rollup across workspaces + SSE /api/fleet/events

Decision: docs/decisions/2026-08-25-second-brain-os-pivot.md
Convoy: .convoys/second-brain-os-v01

Co-authored-by: orchestrator
2026-08-25 16:20:53 -05:00
Randall Stillwell
56b697b81c feat(markdown-backlog): close the sync loop with DB → frontmatter export
Until now the markdown importer was one-way (plans/*.md → DB). Any
agent-driven status flip via claim_task / complete_task would be
clobbered on the next importer sweep. This change closes the loop: the
DB now projects status, priority, agent_prompt, and updated_at back
into the file's frontmatter, preserving body bytes, key order, and
every other frontmatter key.

New: packages/database/src/markdown-backlog/export.ts
  - `rewriteFrontmatter()` — pure function, covered by 10 Vitest cases
    (round-trip identity, status flip, priority flip, agent_prompt
    null/block-scalar/single-line variants, body preservation,
    trailing-newline preservation, idempotent re-application).
  - `exportBacklogItemToMarkdown()` — DB-loading wrapper with atomic
    write (tmp + rename) and tenant fencing. Returns a structured
    result so callers can surface what happened in their response.

Wired into:
  - `claim_task` MCP tool — exports on the ready → in_progress flip.
  - `complete_task` MCP tool — exports on any finalStatus transition.
  - `backlog.updateWorkflowPrompt` tRPC mutation — exports on prompt
    edits made through the app UI.

Robust repo-root resolution (`apps/{mcp-server,web}/src/lib/repo-root.ts`,
plus a copy in `import-markdown-backlog.ts`): walk up from the source
file looking for `pnpm-workspace.yaml`, falling back to env var or cwd.
This fixes a class of bug where `pnpm --filter <pkg>` cd's into the
package directory and breaks naive cwd-based path resolution — the
importer was deleting all 44 rows during smoke testing before this fix
because it found zero files in `packages/database/plans/`.

`config/CursorSync.md`: documents the new two-way contract, the
DB-wins-on-allow-list conflict policy, and the
MARKDOWN_BACKLOG_REPO_ROOT=off escape hatch for production deployments
where `plans/` isn't checked out.

Smoke verified end-to-end against the homelab DB: claim flips file
status to in_progress, complete flips it back to ready, importer
round-trips with stable content_hash (true no-op), agent identity
preserved throughout.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 10:21:22 -05:00
Randall Stillwell
fc2235a346 feat(agent-runs): capture client + model identity on claim/complete
Adds level-B agent attribution: every MCP tool call can identify itself
with a `client` (e.g. cursor-ide, codex, echodo-orchestrator) and `model`
(e.g. claude-4.6-sonnet) string. Both optional, both stored in
agent_runs.metadata as JSONB so the schema doesn't move.

- claim_task: new optional `client` + `model` args. Written into the
  inserted agent_runs row's metadata, and mirrored into the audit log
  entry. On idempotent re-claim, incoming values are merged into
  existing metadata (existing keys override only when explicit), so a
  mid-session model switch updates attribution without losing earlier
  context.
- complete_task: same optional args, with merge-on-close semantics —
  late-bound values override the earlier claim's values so the run row
  reflects whichever model actually closed the session. Audit row also
  carries the merged identity.
- /settings/runs UI: stack the client/model under the actor name in the
  table so attribution is visible at a glance without adding a column.

Smoke-tested: claim with {cursor-ide, claude-4.6-sonnet} then complete
with only model={claude-4.6-sonnet-medium-thinking} yields final
metadata {client: cursor-ide, model: claude-4.6-sonnet-medium-thinking}
on both the run row and the task.completed audit entry.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-03 10:11:35 -05:00
Randall Stillwell
b2aff2045b feat(mcp): claim_task tool + register claim/complete pair
Pairs with the parallel complete_task commit. claim_task opens an
agent_runs row, flips status to in_progress only when it's safe
(ready/draft → in_progress, never overwriting a deliberate
blocked/done/in_progress), and returns the resolved workflow prompt
+ source level. Idempotent re-claim by the same actor returns the
existing run with reused=true and refreshes notes only — started_at
is sacred. Different-actor re-claim errors with ALREADY_CLAIMED
naming the existing actor and run id.

Tenancy fence: if the backlog item exists but in a different workspace
than the resolved handle, we refuse with "doesn't belong to workspace"
rather than 404. Prevents cross-tenant existence fishing.

All three writes (run insert + status flip + audit insert) happen in
one db.transaction() so a partial claim is unreachable.

tools/index.ts now registers both claim_task and complete_task.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 22:23:05 -05:00