Commit Graph

33 Commits

Author SHA1 Message Date
saltbo 53b75fe880 refactor!: adopt the Enbor agency contract
Move internal upstream integration code to generic Agency names, consume @realmroot/enbor-sdk 0.3.0, expose Enbor public errors and Runner UI, and migrate active integration state without compatibility readers.

BREAKING CHANGE: legacy AMA integration names and metadata contracts are removed.
2026-09-03 16:32:57 -04:00
saltbo df9cb3b3d1 docs(architecture): establish ADR and BDD baseline 2026-09-02 22:23:12 -04:00
jarvis a2fa54a729 feat!: rebuild Agent Kanban for Realmroot Toolbox
Replace the v1 Agent/Machine runtime and CLI architecture with the v2 Resource Server, AMA-backed projections, task lifecycle, session observation, BDD specifications, and a single-package layered codebase.

BREAKING CHANGE: remove the v1 CLI, internal Agent/Machine runtime entities, workspace layout, and legacy runtime coordination APIs.
2026-09-02 00:17:52 -04:00
saltbo 972673aecd feat(auth)!: snapshot Realmroot native cutover
Replace Better Auth user, machine, and agent authentication with Realmroot native flows, migrate tenant ownership, and route AMA access through the cutover adapter. Preserve this deployed migration state as the baseline for the narrower user-auth-only redesign.
2026-08-21 00:44:07 -06:00
saltbo f848041499 feat(maintainers): add scoped auth sessions 2026-06-26 11:10:24 -04:00
saltbo 1b74518bc9 feat(maintainers): require maintainer agents 2026-06-26 02:02:10 -04:00
saltbo 59c88dffa0 feat(maintainers): taint maintainer agents 2026-06-26 00:26:27 -04:00
saltbo 8e0b23723d feat(ama): eager, feature-coupled AMA provisioning; only sessions stay lazy
Move AMA resource creation out of the dispatch path into the AK actions that own
them:
- Connect AMA -> provision the owner's AMA project + session-secret vault
  (POST /api/ama/provision, called once from the account page after linking).
- Add Machine -> create the matching environment: local computer = self_hosted
  (+ ama-runner via `ak start`), or Cloud Sandbox = a cloud environment
  (POST /api/machines/cloud). Unlimited; machines.hosting distinguishes them.
- Create Agent -> create the AMA agent first, then persist the AK agent with its
  ama_agent_id; if the AMA call fails the request errors and nothing is written.
- Dispatch only creates the session now: it reads the existing project and the
  stored agents.ama_agent_id, picks an environment among the owner's machines
  (cloud sandbox or local) by runtime, and 409s with "add a machine or cloud
  sandbox" when none fits. No more per-owner lazy cloud singleton.

Agent and machine creation require a linked AMA account (the agent subsystem is
AMA-backed); the kanban board and tasks still work without AMA. Adds migrations
0025 (machines.hosting) and 0026 (agents.ama_agent_id).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 19:27:57 -04:00
saltbo 2b47b40b12 refactor(runtime): consolidate AMA integration schema 2026-06-07 19:50:47 -04:00
saltbo 3bd8ad366e feat(runtime): dispatch AK tasks through AMA 2026-06-07 17:13:42 -04:00
saltbo db228e5177 feat(subagents): store subagents separately 2026-05-17 23:42:22 -04:00
saltbo 2a39054e3d fix: remove deleted labels from tasks 2026-05-04 13:45:26 -04:00
saltbo f930da2413 feat: add board labels for tasks 2026-05-04 11:03:29 -04:00
saltbo f5823fc95e feat(agent): add versioned agent publishing 2026-05-03 20:19:45 -04:00
saltbo 7fbbbfe2eb feat: add registered worker subagents 2026-05-03 10:55:55 -04:00
saltbo 11defd77e7 feat(runtime): track runtime availability 2026-05-03 00:16:07 -04:00
saltbo d3f533e2eb fix(api): enforce one leader per runtime 2026-04-14 15:35:04 -04:00
saltbo c9e9339ec8 refactor: migrate from Pages+Functions to Cloudflare Worker
Unify the app into a single Worker deployment:
- Move functions/api/ → server/, add worker/index.ts entry point
- Merge relay-worker DO (TunnelRelay) into the main worker
- Replace Pages Functions with @cloudflare/vite-plugin build
- Integrate share SSR (OG meta injection) into Hono routes
- Remove dayjs dep from shared (native Date suffices)
- Simplify dev to single `vite dev`, deploy via CF Git integration
- Delete packages/relay-worker/ and Pages-specific _routes.json
2026-04-13 07:58:39 -04:00
saltbo 7a23b5fe1d fix(api): enforce tenant isolation on all task endpoints and fix agent-auth 429 handling
Task endpoints (list, get, update, delete, lifecycle, messages, notes, SSE)
were missing owner_id scoping — any authenticated caller could see and mutate
tasks belonging to other tenants. Add Hono middleware on /api/tasks/:id routes
to assertTaskOwner via board ownership, and thread ownerId through listTasks
and getTask queries.

Also fix two daemon-affecting issues:
- agentAuth /agent/session rate limit raised from 60 to 600 req/min (daemon
  with 3 concurrent agents was hitting the default limit)
- auth middleware now transparently passes 429 from Better Auth instead of
  wrapping it as 401, so CLI backoff logic works correctly
2026-04-12 15:41:20 -04:00
saltbo 09b65eb041 fix(api): record session_id in task_actions to fix incorrect active_session_id
The getTask query derived active_session_id from the latest agent_session,
which returned the wrong session when an agent had multiple sessions.
Now session_id is stored directly on each task_action row and read from
the claimed action, giving the correct session for the chat relay.
2026-04-02 09:26:38 -04:00
saltbo ca7d7aceab feat(api): unify agent Ed25519 key — GPG subkey is single source of truth
Previously agents had two independent Ed25519 keys: one for JWT auth
(generated by crypto.subtle) and one for GPG commit signing (generated
by openpgp.js addSubkey). This violated the original design of one
cryptographic identity per agent.

Now the GPG subkey is the sole key source. Its Ed25519 material is
extracted as JWK for JWT auth. Agent ID = GPG subkey keyID. All agents
(including builtins) go through the GPG identity path.

Other changes:
- username is now required in CreateAgentInput (no more deriveUsername)
- username is globally unique (shared email domain), migration 0015
- Validation order: username check before GPG mutation to avoid orphans
- Runtime guards on openpgp.js internal field access
2026-03-28 16:30:45 -04:00
saltbo 7d18fac4f7 feat: agent mailbox inbox + GPG sync hardening 2026-03-28 11:22:55 -04:00
saltbo 575006906e feat: agent identity — username, GPG subkey, daemon signing
Complete agent commit identity implementation:

- Agent entity: add username (unique per owner, auto-derived from name)
  and gpg_subkey_id fields. Email computed as username@mails.agent-kanban.dev.
- GPG subkey: auto-generated on agent creation via root key addSubkey().
  Subkey ID stored on agent record for daemon use.
- Daemon injection: taskRunner sets up ephemeral GNUPGHOME with imported
  root+subkey chain, injects GIT_AUTHOR/COMMITTER identity and GPG signing
  config via GIT_CONFIG_COUNT env vars. Cleanup on process exit.
- API: GET /api/agents/:id/gpg-key (machine-only) returns armored private
  key + subkey ID for daemon GPG setup.
- CLI: ak create agent --username flag, auto-derive if omitted.
- Session persistence: gpgSubkeyId, agentUsername, agentName saved for
  resume flow.
2026-03-28 03:02:55 -04:00
saltbo 980747574a feat(task): add scheduled_at for deferred task scheduling
Tasks can now specify a one-time scheduled_at timestamp (ISO 8601 with
timezone, normalized to UTC via dayjs). The daemon skips tasks whose
scheduled time has not yet arrived. Released/timed-out tasks have their
scheduled_at cleared so they become immediately re-dispatchable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:11:12 -04:00
saltbo cf3fa34f32 feat: add board type (dev/ops) with workspace abstraction
Boards now have a required `type` field — `dev` for development workflows
(git/PR/code review) and `ops` for operations workflows (no repo). This
drives per-type system prompts, workspace creation (worktree vs tmpdir),
and task validation (dev requires repository_id, ops forbids it).

Key changes:
- Workspace abstraction (workspace.ts) decouples workspace lifecycle from
  repo operations — scheduler and process manager stay unchanged
- System prompt generates per-board-type agent work protocol
- BoardType enum with isBoardType guard centralizes type validation
- gh auth downgraded to warning so ops-only daemons can run without it

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:51:12 -04:00
saltbo 3d9f1d8daf feat(task): add per-board auto-incrementing sequence number
Add a `seq` field to tasks, similar to GitHub issue numbers — each board
maintains its own counter. Displayed as #N on cards and detail drawer.
Title in detail drawer is now read-only (no EditableText).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 01:00:35 -04:00
saltbo 5414ceddc6 feat(cli,api): device fingerprint for machine deduplication and multi-env credentials
Machines are now identified by a hardware fingerprint (sha256 of hostname + MAC),
eliminating duplicate machine creation on API key rotation or environment switching.
CLI config stores credentials per api-url host, enabling seamless environment switching
without re-entering keys.

- Add device.ts: generate deterministic device ID from hardware fingerprint
- Rewrite config.ts: credentials stored by host, auto-migrate legacy flat format
- POST /api/machines: upsert by (owner_id, device_id) via ON CONFLICT
- Heartbeat: bind unbound keys, reject keys bound to different machines
- Frontend reconnect: simplified to show `ak start --api-url` command only
- Migration 0006: add device_id column with NOT NULL + unique index

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 22:35:04 -04:00
saltbo 489f9ac7d2 refactor(agent): require runtime, define AgentRuntime enum, improve daemon CLI output
Make agent runtime a required field across the full stack — DB, API,
shared types, CLI, and frontend. Define AgentRuntime enum ("claude" |
"codex" | "gemini") as single source of truth with labels. Remove
defaultProvider from daemon since runtime is now per-agent. Enrich
ak start/stop/status output with structured daemon state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:49:48 -04:00
Jasper Van 711a1bf57c Rename task_notes to task_actions with actor_type/actor_id (#89)
Replace the task_notes table and agent_id/session_id columns with
task_actions and actor_type/actor_id to track all identity types
(user, machine, agent:worker, agent:leader). This enables user and
machine actions to appear in the activity log and board animations.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 10:39:46 -04:00
saltbo 9115d21a64 feat(auth): add agent kind (worker/leader) and CLI runtime wrapper
Introduce agent `kind` field to differentiate worker agents (daemon-spawned)
from leader agents (CLI-launched via `ak claude/codex/gemini`). Leader agents
can complete, reject, cancel, and assign tasks; workers can only claim and
review. Session capabilities are granted based on kind.

- Add `kind` column to agents table (worker | leader)
- Split IdentityType: agent → agent:worker / agent:leader
- Runtime auto-detection via env vars (CLAUDECODE, CODEX_CI, GEMINI_CLI)
- `ak claude/codex/gemini` wraps runtime with session lifecycle
- `ak whoami` for agents to query their own identity
- JWT `aid` claim verified against session binding (prevent escalation)
- Auth middleware resolves kind in single JOIN query (no N+1)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 19:57:50 -04:00
Jasper Van 9d928951c0 refactor: rename task_logs to task_notes across API, database, and codebase (#59)
Breaking change: renames the task_logs concept to task_notes throughout
the entire stack — database table, API endpoints, shared types, CLI
client methods, SSE event types, and frontend components.

- Add migration 0002 to rename table task_logs → task_notes
- API: POST/GET /api/tasks/:id/logs → /api/tasks/:id/notes
- Types: TaskLog → TaskNote, TaskWithLogs → TaskWithNotes
- Repo: addTaskLog → addTaskNote, getTaskLogs → getTaskNotes
- CLI: addLog → addNote, getTaskLogs → getTaskNotes, formatTaskLogs → formatTaskNotes
- SSE: event type "log" → "note"
- Frontend: logs state → notes, initialLogs → initialNotes, sseLogs → sseNotes

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:01:40 -04:00
saltbo d84dc66373 refactor: replace prettier with biome for formatting and linting
Prettier's aggressive line-splitting (printWidth 100, single quotes) didn't
match the project's existing compact code style. Switch to Biome which
provides formatting + linting in one tool with better chain-call handling.

- Remove prettier, add @biomejs/biome
- Configure biome: double quotes, lineWidth 150, recommended lint rules
- Update lefthook pre-commit to use `biome check`
- Full codebase format pass with new config

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 19:51:41 -04:00
saltbo 300bbb0572 fix(api): deserialize JSON fields in repo layer, install agent-specific skills
JSON fields (Agent.skills, Agent.handoff_to, Task.labels, Task.input)
were leaking as raw strings in API responses. Now deserialized at the
repo layer boundary via a shared parseJsonFields helper in db.ts.
Also installs each agent's own skills (from agent.skills field) in the
daemon before spawning, alongside the shared agent-kanban skill.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 18:45:40 -04:00