Deft is an open-source AI-native workspace. Native chat + tasks + an AI agent that plans and executes multi-step workflows across native data and connected calendar feeds and BYOA-provided external tools. The agent has direct SQL access to native data — not API calls — making it fundamentally faster and smarter than bolt-on AI features.
One Next.js app. One Postgres database. Multi-tenant SaaS with org_id on every table.
Licensed under the GNU Affero General Public License v3.0 only (AGPL-3.0-only). Network deployments of modified versions must offer their users the corresponding source under AGPL section 13.
deft/
├── apps/
│ ├── web/ # Next.js 14 (App Router, TypeScript, Tailwind CSS)
│ └── api/ # Hono (TypeScript, REST endpoints, WebSocket via Socket.io)
├── packages/
│ ├── db/ # Drizzle ORM schema + client + migrations
│ ├── mcp/ # MCP server SDK + tool definitions for BYOA agents
│ └── shared/ # Shared types, Zod schemas, constants
├── docker-compose.yml # Self-host: postgres + app
├── .env.example
├── LICENSE # GNU AGPL v3.0 only
└── pnpm-workspace.yaml
Stack:
- Frontend: Next.js 14, App Router, TypeScript, Tailwind CSS, TipTap (editor)
- API: Hono on Node.js, TypeScript
- Database: PostgreSQL + pgvector (Drizzle ORM)
- Real-time: Socket.io in-process (single app instance; no cross-instance adapter)
- Auth: Custom JWT + bcrypt (jsonwebtoken + bcryptjs, Google OAuth)
- Background jobs: PostgreSQL
job_queuewith in-process workers - File storage: Cloudflare R2 or local (presigned uploads)
- AI: Anthropic Claude API (Sonnet for reasoning, Haiku for classification)
- Email: none. Invites and password recovery are admin-generated one-time URLs (
apps/api/src/routes/invites.ts,POST /api/members/:id/recovery-url), shared out-of-band. Self-hosted Deft never sends mail. - Monorepo: pnpm workspaces
org_idon EVERY table (multi-tenant, row-level isolation)- Soft deletes everywhere (agent needs historical context)
created_at,updated_aton every table- UUIDs for primary keys (cuid2)
- All user-generated text stored as-is, never truncated
- Events table for connected tool data (unified schema)
- TypeScript strict mode everywhere
- Zod for all request/response validation
- Drizzle ORM — no raw SQL except in agent queries (agent needs direct access)
- API routes:
POST /api/spaces,GET /api/spaces/:id/messages, etc. - WebSocket events:
message:new,message:edited,typing:start,task:updated - Error responses:
{ error: string, code: string }— never raw stack traces - Components: functional React, no class components, prefer server components where possible
- Styling: Tailwind only, no CSS modules, no styled-components
- State: React hooks + context for client state, SWR or React Query for server state
- File naming: kebab-case for files, PascalCase for components
- Slash menu for editor surfaces. All TipTap editor surfaces (chat, task description, task comment, notes, canvas) mount the
BlockSlashMenuextension viacreateBaseExtensions({ surface })inapps/web/src/lib/editor/shared-config.ts. Add new slash commands by registering them onslashRegistryinapps/web/src/lib/editor/commands.ts— declare which surfaces they appear in via thesurfacesarray. Block commands live inbuilt-in-commands.ts; AI actions live inai-commands.ts. AI actions hitPOST /api/ai/transform(one endpoint, action-typed).
The agent is NOT a chatbot. It's a workflow engine.
Two agent roles (collapsed from five in Phase 9, 2026-04-28):
- Defty — built-in platform agent. Runs in-process via Anthropic API, has direct SQL access plus 42+ native tools, multi-step planning (
create_plan), memory (remember/recall), and streaming responses. Lives behindapps/api/src/workers/handlers/agent-reply.tswith a well-knowndeft-agent@system.localuser. Noagent_employeesrow, nokindcolumn, no choice. Operates under the org-wide trust level. Reactive only — responds to@mentionsand triggers. - BYOA employees — every
agent_employeesrow. External agents (Claude Code, Claude Desktop, Codex, Cursor, custom MCP runtimes) connecting via MCP. Authenticate with API key, get tools via/api/mcp/v1. Per-employee trust levels, daily action caps, cost tracking, circuit breakers. Push is gone — Deft never pushes to BYOA agents. They discover work viapoll_pending_workMCP tool:@mentions, heartbeat ticks, andtrigger_subscriptions-routed events all queueagent_actionsrows that BYOA clients pull.
Agent engine lives in apps/api/src/lib/ (agent-context, agent-plans, agent-tools, agent-actions, agent-runner, agent-stream-loop, agent-approval, agent-approval-resolver). The packages/ai stub was removed 2026-04-16.
Participant model (Phase 1 unification, 2026-05-07). Agents are first-class
users rows distinguished by users.kind (human | agent | system). The Defty
system user has an org_members row in every org (auto-created by
ensureDeftyMembership on signup, invite acceptance, or via the backfill
script apps/api/src/scripts/backfill-defty-membership.ts); BYOA agent
employees do too. Both appear in /api/members (which now returns kind),
the @-autocomplete, and the DM picker. The hardcoded 'agent' mention shim
was removed; agent-reply dispatch detects mentions by joining parsed mention
IDs to users.kind = 'agent', with the legacy @deft regex retained as a
backwards-compat fallback. See docs/superpowers/specs/2026-05-07-agent-chat-unification.md.
Phase 2 (2026-05-07). agent_conversations and agent_messages tables
are dropped. Each /agent conversation is now a spaces row of type
agent_conversation with the user + agent (Defty or BYOA) as members.
Each agent turn is a messages row with structured Anthropic content
blocks in metadata.agent_blocks, plus citations, tool_calls,
model, tokens_in, tokens_out. Tool-result rows carry
metadata.kind = 'tool_result' so the chat-view filter excludes them.
The /agent UI is unchanged because the API contracts at
/api/agent/conversations[/:id/messages|trace.json] preserve their
response shapes; only the underlying data source changed.
agent_actions.message_id continues to link to chat messages — same
UUID space.
Phase 3 (2026-05-07). Two unified MCP tools added: send_message
(target = {space_id} | {thread_id} | {user_id} — replaces
message_post + post_thread_reply + planned open_dm) and
fetch_unread (unread chat messages + pending agent_actions in one
roundtrip — replaces poll_pending_work). The old tools still work
this release but log a deprecation warning. The deft-mcp-client
bundled skill prompt nudges agents toward the new tools.
Phase 4 (2026-05-07). UI collapse: the dedicated /agent route
and AgentChat / ConversationList components are deleted. Chat is
now the only agent-conversation surface — SpaceChat renders agent
messages with inline tool-use chips, citations footer, and model+tokens
detail via the new <AgentMessageBlocks/> component. Inline approval
cards (<AgentActionCard/>, extracted from the deleted AgentChat)
render on chat messages with pending agent_actions. The approval
inbox moved from /settings/agent to a top-level /approvals page;
the sidebar nav entry swapped "Agent" for "Approvals" with the same
red-badge count. Defty's DM is pinned at the top of the Direct
Messages section, followed by other BYOA agents.
Phase 5 (2026-05-07). Universal /inbox: one queue at /inbox
unifies notifications (mentions, task_assigned, task_updated, blocked,
cross_reference, wiki_update, system), DM unread (per-space rollup
from space_members.last_read_at vs messages.created_at for dm /
group_dm spaces), and pending agent approvals (from agent_actions).
Backed by GET /api/inbox (with count_only=1 for the badge fetch
and kind= for tab filtering) plus POST /api/inbox/read for mark-read
(ids[] with notif: prefix, or all: true). Tab strip:
All / Mentions / DMs / Tasks / Approvals. The Tasks tab fetches all and
filters client-side for both task_assigned and task_updated.
Approval rows render the existing <AgentActionCard/>; everything
else renders <InboxRow/>. The sidebar Approvals entry was replaced
by Inbox with one aggregated red-badge count via useInboxCount.
/approvals is a server redirect to /inbox?tab=approvals so external
links keep working. No schema migrations — pure read-side aggregator.
Phase 6 (2026-05-07). Multi-agent affordances. (1) Agents partitioned
in SpaceMembersPanel into a separate "Agents" section with an
<AIBadge/> per row, mirroring Phase 4's CreateDmModal pattern;
backend member-add accepts any user kind unchanged. (2) Reply-storm
detector at apps/api/src/lib/storm-detector.ts: counts agent-authored
thread replies (per agent, per thread root) in a rolling 10-minute
window. On count >= 5, the BYOA sendMessage MCP tool (thread_id
target) and the Defty post_thread_reply executor return a
STORM_DETECTED error so the agent's runtime can back off. Top-level
posts and DMs are not throttled. (3) <AIBadge/> component extracted
into apps/web/src/components/ai-badge.tsx and reused by both
CreateDmModal and SpaceMembersPanel. No DB migration.
Skills primitive (agent-only). A single skills table with three source tiers — bundled (shipped with Deft, org_id IS NULL), marketplace (installable catalog), org (tenant-authored). Carries an agent_config JSONB (tools, capability packs, triggers, prompt additions, heartbeat checklists). Agents install skills via the agent_employee_skills junction. Bundled skills are generated dynamically — one per available capability pack (Deft Workspace carries the 9 task tools) plus deft-mcp-client (Block 3 on-ramp for BYOA agents to talk back into the workspace via MCP). Task templates are a separate first-class primitive (task_templates table) — instantiated into any project via POST /api/projects/:id/apply-template. Project-level customization via project_skills / skills.project_config was retired 2026-04-18 in favor of fixed engineering defaults. See docs/superpowers/specs/2026-04-18-simplify-skills-templates-design.md.
Observation pipeline: Every chat message classified (Haiku): actionable? Intent? Entities? Urgency?
Planner: Complex requests decomposed into ordered steps. Plan shown to user → user edits/approves → agent executes with live progress (streamed to task-detail panel per Task 3.10) → pauses on failure or rolls back per plan mode.
Proactive comments: The nudge-check worker drops agent-authored comments on stalled/overdue tasks and on auto-accepted task extractions (Task 3.11), deduped 7d per task. Inline agent task-suggestion cards appear in chat for classified actionable messages (Task 3.12).
Tool registry: All agent actions registered with name, params, approval tier, provider. Agent only sees tools for services the user has connected.
Three-tier approval:
- Auto-execute: task status from PR merge, meeting prep, reminders
- Quick-approve: create task, schedule meeting (one-click card)
- Full-review: multi-step plans and external writes (preview + edit)
Trust levels (per org): Conservative → Standard → Autonomous
Native actions (direct SQL): Create/update/assign tasks, post messages, set reminders Connected actions (API): Create calendar events and read connected work events
Event-driven triggers (PostgreSQL scheduled jobs):
- Task overdue → DM assignee + alert lead
- Task stalled 48h → ask for update
- PR merged → parse
PREFIX-Nrefs in title/body, move each matched task (intodo,in_progress, orin_review) todoneand leave an attribution comment linking the PR. Wired into the GitHub sync path (apps/api/src/workers/github-sync.ts→closeTasksForMergedPR); runs only on thepr_opened|pr_closed → pr_mergedtransition so re-syncs don't re-fire. Tasks alreadydoneorcancelledare never touched. - Meeting in 15min → generate prep briefing
- 9am daily → auto-generate standup from activity
Tasks are the agent's primary output surface and the product's action surface. Post-Phase-6 they ship with:
- Fixed project defaults. Every project uses the 6-status engineering vocabulary (
backlog,todo,in_progress,in_review,done,cancelled), p0–p3 priority, and Kanban default view. View switcher (Board / List / Timeline / Calendar / Pipeline) remains a per-user selection. Per-project customization (project_skills,skills.project_config, first-attached-wins resolution, custom fields, allowed-transitions overrides) was retired 2026-04-18 — seedocs/superpowers/specs/2026-04-18-simplify-skills-templates-design.md. - Recurrence UI + clone fix (Task 4.12) — recurring task pattern stored on
tasks.recurrence(daily|weekly|biweekly|monthly) withrecurrence_source_idlinking generated copies. - Workflow executor (basic) — PostgreSQL-queue-backed runner supporting the
task.status_changedtrigger with four actions:add_comment,assign_to,add_label,notify(Task 5.7). Broader trigger coverage + skill-defined triggers land in Phase 8. - Task reactions (Task 6.3) — emoji reactions on task cards/detail (
task_reactionstable, upsert/delete endpoints). - @mentions in description + comments (Task 6.4) — autocomplete + notification dispatch mirrors chat mentions.
- Activity diff view (Task 6.2) — inline old→new rendering in the task activity log, replacing flat "changed status" strings.
- GitHub PR→Done (Task 5.6) — polling sync worker parses
PREFIX-Nin PR title/body on thepr_opened|pr_closed → pr_mergedtransition and closes each referenced task with an attribution comment. Polling only, no webhook yet. - Project archive + soft-delete (Task 5.8) — settings modal with 7-day recovery window. Soft-deleted projects hide from views but preserve tasks for audit.
- Task 0.1 security fix (resolved) — watchers + assignees routes enforce
org_id+ auth. - Task 0.4 dashboard fix (resolved) — "My Work" filter on the bento dashboard now scopes to the current user.
- Security hardening (Phase 7, resolved) — 10 vulnerabilities fixed: XSS prevention via DOMPurify on all
dangerouslySetInnerHTMLsites (6 components), IDOR fixes on workflow-run/agent-message/wiki-citation deletes (verify ownership before delete), space membership enforcement on all space/message/pin endpoints + WebSocketspace:join, upload path traversal fix (path.basename+ Content-Dispositionattachment), daily notes optimistic locking (CAS version check, 409 on conflict).
Dead primitives retired: the native_tools[] agent column was dropped (migration 0038) and the TEMPLATE_DEFAULT_PACKS constant removed (2026-04-16). project_config JSONB, project_skills table, and the three project-workflow bundled skills (engineering, marketing-campaign, sales-pipeline) were retired 2026-04-18 — projects now use fixed engineering defaults. Capability packs remain expressed as bundled agent skills installed via agent_employee_skills.
- UI fixes (Phase 7) — sidebar three-dot menu portal click propagation fixed (menu items now respond to clicks). Scroll containers added to 9 settings pages that were clipping content.
The original Phase 8 plan was OpenClaw autonomy inside an in-process gateway. Phase 9 (2026-04-28) deleted the gateway; the autonomous loop is now the BYOA agent's responsibility. What the Deft side actually shipped — the heartbeat lifecycle and its guard rails — survived Phase 9 and now applies before BYOA-bound agent_actions rows are queued for MCP pickup.
Tasks 8.1–8.6 shipped on the heartbeat worker:
- Heartbeat lifecycle (Task 8.1) — PostgreSQL scheduled jobs dispatch due employees based on
heartbeat_interval_min. Post-Phase-9, all employees are BYOA; heartbeat ticks queue pending work for MCP polling. - Per-tick logging (Task 8.4) — every tick writes to
agent_heartbeat_turns(fired_at, prompt_sha, action_count, tokens_in/out, cost_cents, outcome, summary) and broadcastsagent:heartbeat:turnvia Socket.io. - Cost guardrails (Task 8.5) —
daily_budget_centsper employee (default $100/day), reset at UTC midnight. Circuit breaker:unhealthyflag tripped after 3 consecutive errors, blocks all autonomous dispatch until manually cleared viaPATCH /api/agent-employees/:id { mark_healthy: true }. - Loop detection (Task 8.6) — prompt_sha idempotency skips re-dispatch when nothing changed since last no_op tick. Consecutive identical action detector trips the circuit breaker.
Not yet shipped: skill-defined trigger dispatcher (arbitrary triggers from skill manifests, not just the hardcoded set of cron:standup, member.joined, webhook, task.status_changed).
- Agent reads native data via direct SQL, not API calls. This is the core advantage.
- Connected tools write to a unified
eventstable. Agent queries native + events together. - Chat is the observation surface. Every message feeds the agent's context.
- Tasks are the action surface. Agent creates and manages tasks as its primary output.
- Dashboard is the intelligence surface. Agent-generated briefings, not static widgets.
- Product works fully without AI. If LLM is down, chat + tasks function normally.
- Multi-tenant from day 1. org_id on every query. No shortcuts.
ARCHIVED 2026-04-28. OpenClaw was deleted in Phase 9. The in-process gateway, per-org provisioning, gateway-ping, ClawHub HTTP pass-through, and the
kindcolumn are all gone. Items below stayed because they're useful in the BYOA-only world (trust levels, durable reminders, semantic wiki search, per-org spend caps, SKILL.md sanitizer, ClawHub allowlist as a skill-import source, approval badge nav, post-creation employee edit). Items that depended on a live gateway (anyconnection_url/gateway_token/provider_instanceplumbing) were stripped.
Block 0 of the OpenClaw Unlock plan closed the structural foundation bugs
and added invisible-today primitives. See
docs/superpowers/plans/2026-04-19-openclaw-unlock.md for the full plan.
Shipped:
- Trust levels enforce per-tier. Conservative auto-execs only
auto; Standard addsquick; Autonomous addsfullEXCEPT destructive admin tools (manage_agent_employee,manage_mcp_connection,remove_member, anydelete_*, or any call withparams.mode: delete|pause|revoke). 35-case matrix test inapps/api/test/agent-approval-matrix.test.ts. - Reminders durable. Moved from in-process
setTimeoutto the Postgres-backedscheduled-jobsqueue. Boot rehydrates pending reminders fromreminders.is_sent=false. Newcreate_remindernative agent tool. - Wiki search semantic.
wiki_searchtool routes throughretrieveContextwhich blends FTS + pgvector cosine (0.4 / 0.6 weight × confidence). Falls back to FTS-only when embeddings API is unavailable. - Wizards unified. Old 7-step
/settings/agent/deploydeleted;NEXT_PUBLIC_FEATURE_OPENCLAW_EMPLOYEESflag removed; canonical flow is the 3-step/settings/agent-employees/create. - Standup fallback retired. If no employee subscribes to
cron:standup, orgs admins get a singlestandup_unconfigurednotification (7-day dedup) pointing at /library. No more nativellm()path bypassing agent-runner. - Per-org LLM spend caps. New
org_spend_capstable;checkOrgSpendCap/recordOrgSpendFromUsagehelpers;llm()gains optionalorgIdfor opt-in enforcement. Default $100/mo new-org cap. Admin UI ships in Block 3. - SKILL.md sanitizer. Pre-import library that neutralizes prompt-injection, credential-exfil, sensitive-file-access patterns. Block 1 consumes at ClawHub skill import time. 20 malicious + 5 benign fixtures.
- ClawHub allowlist. Daily cron pulls VoltAgent curated list into
clawhub_allowlisttable; bundled 14-entry static fallback on network failure. Block 1 Library UI filters against this table. - Approval badge in main nav.
usePendingApprovalsSWR hook polls/api/agent/actions/pendingevery 15s; red count badge on the Agent nav entry app-wide. - Edit agent post-creation.
PATCH /api/agent-employees/:idacceptsname,avatar_url,starter_prompts,expertise_description,max_daily_actions,heartbeat_enabledwithout role gate; trust/cadence/mark_healthy still require owner/admin.
Migrations added: 0047_clawhub_allowlist.sql, 0048_org_spend_caps.sql.
ARCHIVED 2026-04-28. Phase 9 deleted the gateway control plane:
openclaw-{gateway,dispatch,client,chat-envelope}.tsare indocs/deprecated/openclaw/,pushSkillSecretsToGatewayis removed, the per-org provider-instance reuse logic is gone (theprovider_instancestable was dropped), the reasoning-trace component + hook were deleted (no live session events to subscribe to), and the gateway approval-forwarder is gone. Surfaces that survived because they're still useful in BYOA-only: the markdown personality editor (/settings/agent-employees/[id]/personalityreading/writing the 7 canonical files locally, no longer pushed to a gateway), theskill_secretstable for storing BYOA per-skill credentials, ClawHub allowlist for skill import (allowlist row → marketplace skill row, no gateway install). Therequest_skill_installruntime tool stayed but no longer pushes to a gateway.
Block 1 delivers the OpenClaw Gateway control plane: a WebSocket JSON-RPC client that every route/worker shares, plus the surrounding surfaces that exercise it (skill install/remove, markdown file editing, approval forwarding, reasoning trace, per-org gateway reuse).
Shipped:
- Gateway RPC client.
apps/api/src/lib/openclaw-gateway.ts. WebSocket JSON-RPC 2.0 with multiplex-by-id, lazy connect, exponential-backoff reconnect (1s→2s→4s→8s→30s), 30s per-call timeout, per-deployment-id cache. Typed namespaces:skills,agents.files,exec.approval,config,sessions,cron. Transport is injectable (test seam). - agents.files.* UI + API.
GET/PUT /api/agent-employees/:id/files[/:filename]routes +/settings/agent-employees/[id]/personalitypage with a markdown editor for the 7 canonical files (SOUL, AGENTS, USER, TOOLS, IDENTITY, HEARTBEAT, BOOT). 128KB cap, filename whitelist. - Live skill install/remove on attach.
ensureSkillInstalledfiresgateway.skills.install(slug, version)live for connected openclaw employees alongside the junction insert. NewremoveSkillFromEmployeehelper +DELETE /api/skills/:id/installroute mirrors the semantics. Fire-and-forget — gateway errors don't roll back the DB write; reconciliation loop retries. skill_secretstable. Migration 0049. Encrypted per-org, per-skill credential store with helpers inapps/api/src/lib/skill-secrets.ts. Least-privilege:getSecretsForSkillonly returns the keys declared by a skill's manifest.- ClawHub browse + import.
GET /api/clawhub/browsereads the VoltAgent-seeded allowlist;POST /api/clawhub/import { slug }materializes as a marketplace skill. New "ClawHub" tab on the Library page with per-entry Import button. - Pre-deploy install flow.
resolveSecretsForInstall(orgId, skillId, requiredKeys)— OAuth-first (connected_accounts) with skill_secrets fallback, env-var → provider prefix map (GITHUB_/GOOGLE_/LINEAR_).pushSkillSecretsToGatewaycallsconfig.set('skills/<slug>/<KEY>', value). OrchestratorinstallMarketplaceSkillWithSecrets(employeeId, skillId)wires it end-to-end. New routes:POST /api/skills/:id/install/marketplace,POST /api/skills/:id/secrets. - Runtime install tool.
request_skill_install(slug, agent_employee_id?, rationale?)— new native tool, always queues for approval (tier='full' + DESTRUCTIVE_ADMIN_TOOLS). Executor looks up the slug on the allowlist (imports as marketplace skill on first use) and runs the pre-deploy flow. Slugs off the allowlist are rejected; full-ClawHub install stays admin-only. - Skill reconciliation loop.
reconcileSkillsForEmployeefires best-effort from the openclaw heartbeat branch. Diffsagent_employee_skillsagainstgateway.skills.list(), auto-reinstalls missing viagateway.skills.install, emitsskill_driftsystem notification to org admins after > 2 consecutive drifting ticks (24h dedupe). - Exec/plugin approval forwarding.
startApprovalSubscriberFor(employeeId)subscribes toexec.approval.request+plugin.approval.requestevents on the gateway and mirrors them asagent_actionsrows (action=openclaw_exec_approval/openclaw_plugin_approval, tier=full). Existing approval-inbox UI renders them with no change. Approve/reject forwards back viagateway.exec.approval.resolve(approvalId, approved, reason). Bootstrap fromworkers/index.ts. - Reasoning trace.
startTraceForwarderForSession(employee, sessionId)subscribes tosession.tool+session.message, fans outagent:tracevia Socket.io toorg:<orgId>filtered by sessionId. FrontenduseReasoningTrace(sessionId)hook +<ReasoningTrace/>expander component. - Per-org gateway for new deploys.
deploy-provisionworker checks for an existing openclaw provider_instance in the org on the same provider; if found, the new employee inherits itsconnection_url+gateway_token_encrypted+provider_instance_id, skippingprovider.provision(). Pre-existing per-agent deploys are NOT migrated (Open Question #4).
Migration added: 0049_skill_secrets.sql.
Known-deferred (Block 2): full-ClawHub HTTP pass-through (currently stubbed); allowlist-auto under Standard/Autonomous trust; drawer-tab integration of the Personality editor; chat-surface integration of <ReasoningTrace/>; migration path for existing per-agent deploys.
Phase 9 note 2026-04-28. Block 2 was already runtime-agnostic — the new tools (notes/canvas/decision/post_thread_reply) are exposed via MCP and work for BYOA agents unchanged. The
member.joinedonboarding trigger keeps working becausetrigger_subscriptionswas preserved (it's the routing key for the trigger system, not OpenClaw plumbing). Dashboard inline approve/reject and the heartbeat checklist builder still apply. Nothing in this block needed to be removed.
Block 2 closed the dead zones where agents couldn't act and surfaced agent activity on the primary product surfaces. All 9 tasks shipped.
- Note agent tools.
search_notes(ILIKE + scope filter),read_note,create_note(tier quick),note_to_wiki(auto-slug disambiguation, tier quick). Uses existingnotestable. - post_thread_reply(parent_message_id, content). Full-tier; inherits parent's
space_id, broadcastsmessage:newsocket event. - Canvas read/write.
read_canvas(space_name)returns exists=false when no row;write_canvas(space_name, content, title?)upserts (one canvas per space). String content is auto-wrapped into a minimal TipTap doc. - Blocked-message → task-create proposal.
blocked-alertworker now ALSO queuesagent_actions { action:'create_task', approval_status:'pending', source:'blocked_classifier' }on the blocked user so they get a one-click "track this as a task" card. - unblock_dependents workflow action. New action kind for workflow rules. When the triggering task enters
done, DMs each open+assigned dependent task's assignee with asubtype:'unblocked'notification. - Decision ↔ task tools.
link_decision_to_tasks(decision_id, task_ids, context?)→ cross_reference edges (idempotent).mark_decision_implemented(decision_id)→ stampsdecisions.implemented_at(migration 0050). - member.joined onboarding trigger.
POST /api/membersfans outemployee-triggerjobs to every agent whosetrigger_subscriptionscontainsmember.joined. Opt-in via HR skill install. - Dashboard inline approve/reject.
/api/agent/actions/recentreturns recent actions; the existing "Agent Activity" bento card on/dashboardrenders inline Approve/Reject buttons on pending items. - Structured heartbeat checklist builder. New
<HeartbeatChecklistBuilder/>component replaces the textarea forHEARTBEAT.mdon the Personality editor. Rows →- [ ] every Nmin: …markdown the existing heartbeat parser already understands.
Migration added: 0050_decision_implemented.sql.
OpenClaw Unlock — Block 3 power users + ecosystem polish (shipped 2026-04-19; partially ARCHIVED 2026-04-28)
Phase 9 note 2026-04-28. Clone agent + save-as-template stayed (still useful for BYOA scaffolding). Webhook-callable agents stayed — the dispatch path enqueues
employee-triggerjobs which now queueagent_actionsrows for BYOA pickup.deft-mcp-clientbundled skill stayed (more relevant than ever). Agent trace export stayed. Removed: the "developer credentials" page no longer carrieswscatexamples or a JSON-RPC frame catalog (the gateway is gone) — it now shows the MCP endpoint URL + a regenerable bearer token, plus a Claude Desktop config snippet. The reasoning-trace component (Block 1) is also gone, so any chat-surface integration of<ReasoningTrace/>planned in Block 3 is moot.
Block 3 exit-gate met at 5/10 tasks with deft-mcp-client live. Remaining 5 deferred (see docs/superpowers/block-3-complete-2026-04-19.md).
- Clone agent + save as template.
POST /:id/cloneduplicates an employee with a fresh slug + all installed skills;POST /:id/save-as-templatewrites an org-scoped template row. Migration 0051 makesagent_employee_templates.org_idnullable (NULL = first-party/community; non-NULL = org-scoped) with COALESCE-keyed unique on (org_id, slug). - Developer credentials page.
GET /api/agent-employees/:id/developer[?reveal=1]+/settings/agent-employees/[id]/developer— masked token by default, reveal gated to admin/owner. Carries wscat one-liner + example JSON-RPC frames for SDK scaffolding. - Webhook-callable agents. Migration 0052 +
agent_webhookstable; migration 0060 addedhmac_key_encrypted. Authenticated mgmt surface under/api/agent-webhooks, public dispatch at/api/agent-webhooks/:slugthat enqueues anemployee-triggerjob withtrigger_kind='webhook'+ full payload in context. Auth: HMAC-SHA256 signature inx-deft-webhook-signature: sha256=<hex>header (recompute over raw body using the per-webhookhmac_key); legacy raw-secret inx-deft-webhook-secretaccepted with deprecation warning during transition window. scrypt-hashed legacy secret + AES-encrypted HMAC key both stored at rest; constant-time signature comparison. deft-mcp-clientbundled skill. On-ramp for any OpenClaw deployment (incl. BYOA) to talk back into its Deft workspace over MCP — seeded into the bundled catalog.SkillAgentConfigextended withrequires_env?: string[]+mcp_servers?: Array<{ name, transport, url|command, headers }>.- Agent trace export.
GET /api/agent/conversations/:id/trace.json— formatdeft.agent_trace.v1, messages + actions + conversation metadata as one JSON download.
Migrations added: 0051_org_scoped_templates.sql, 0052_agent_webhooks.sql.
Collapsed five agent kinds (native, openclaw, claude_sdk, custom_mcp, plus the unkinded built-in Defty) down to two clear roles:
- Defty — built-in platform agent. In-process via Anthropic API. No
agent_employeesrow; routes throughagent-reply.tswith a well-known system user. Serves@deftmentions and platform workflows. - BYOA employees — every
agent_employeesrow. External agents (Claude Code, Claude Desktop, Codex, Cursor, custom MCP) connect via MCP with an API key, get tools through/api/mcp/v1, and pull pending work throughpoll_pending_work. Deft never pushes.
Removed:
kindcolumn onagent_employees(and the'native' | 'openclaw' | 'claude_sdk' | 'custom_mcp'enum)- 10 OpenClaw sidecar columns:
connection_url,gateway_token_encrypted,connection_status,template_slug,template_version,provider_hint,provider_instance_id,connection_error,last_gateway_ping_at,gateway_ping_fail_count provider_instancestable- Worker handler
gateway-ping.tsand the cron registration - Gateway WebSocket JSON-RPC client (
openclaw-gateway.ts), dispatch (openclaw-dispatch.ts), HTTP client (openclaw-client.ts), chat envelope (openclaw-chat-envelope.ts) — all archived todocs/deprecated/openclaw/ pushSkillSecretsToGatewayhelper- Frontend:
gateway-health-card.tsx,reasoning-trace.tsx,use-reasoning-trace.ts web-browsingandshell-execreferences from seed templates (these were never in theCAPABILITY_PACKScatalog; they pointed to OpenClaw Layer-2 plugins that no longer exist)/provider-readinessand/retry-provisionAPI endpoints- 6 test files (openclaw-envelope, openclaw-heartbeat, gateway-ping, agent-deploy-routes, byo-provider, railway-provider, skill-install)
Kept (deliberately):
is_byoa(now always true),byoa_model_info,mcp_token_hashtrigger_subscriptionsanddefault_trigger_subscriptions— routing key for the trigger system, not OpenClaw plumbing. Webhooks, member.joined, cron triggers all still route through itagent_webhookstable (Block 3)agent_employee_templatestable (templates still useful for scaffolding BYOA personalities)skill_secretstable (still useful for storing BYOA per-skill credentials)- ClawHub allowlist (now imports as marketplace skills directly, no gateway install)
- The 7-file markdown personality editor (BYOA runtimes can read these locally)
- All trust-tier/budget/circuit-breaker/idempotency/loop-detector heartbeat guards
New worker behavior: instead of branching by kind to push to native (runAgentQuery) or OpenClaw (dispatchViaOpenClaw), every BYOA-bound action queues an agent_actions row that poll_pending_work discovers:
| Source | action |
source |
|---|---|---|
@mention in chat |
chat_mention |
mention |
| Heartbeat tick (after guards pass) | heartbeat_tick |
heartbeat |
Trigger fired (member.joined, webhook, skill cron, …) |
trigger_dispatch |
trigger |
| Task assigned to agent | task_assigned |
task_assignment |
Migration: 0059_remove_openclaw_columns.sql.
See plan: docs/superpowers/plans/2026-04-28-phase9-simplify-agents.md (this prompt).
- Use
pnpm db:push-fullfor fresh installs andpnpm db:upgradefor supported release upgrades.push-fullapplies the Drizzle schema plus supplemental search/index SQL. The tracked upgrade baseline starts atv0.2.0-preview.1and uses a checksumeddeft_schema_migrationsledger. Rawpnpm db:pushandpnpm db:migrateare not supported operator upgrade paths; historical pre-preview databases require manual review.
- Don't put domain-specific CRM logic in core. CRM capabilities belong in declarative modules; core stays generic.
- Don't over-abstract. Build for the current scope, refactor when needed
- Don't cache prematurely. Postgres is fast enough for our scale
- Don't replace the existing auth system without a migration plan. It's custom JWT + bcrypt, not a library — changes affect every authenticated route.
- Don't use Supabase (blocked in India)
- Don't deploy to Vercel for the API (need WebSocket support). Use Railway or Fly.io
- Don't import full TipTap — use only the extensions we need
- Agent conversations live in messages with metadata.agent_blocks (since Phase 2, 2026-05-07). Don't reintroduce parallel agent-only chat tables; use the unified messages schema.
- Don't reintroduce agent kind/type enums or in-process agent runtimes. Every
agent_employeesrow is BYOA — the user's runtime owns execution. If managed deployments come back as a need, build it as a separate service, not as a column onagent_employees.