- Coalescing queue: use HasPendingTaskForIssue (queued/dispatched only)
instead of HasActiveTaskForIssue so comments during a running task
enqueue exactly one follow-up task that picks up all new comments.
- Stale task cleanup: runtime sweeper now fails orphaned tasks when
their runtime goes offline (daemon crash/network partition).
- Cancel-aware daemon: handleTask checks task status after execution
and discards results if the task was cancelled mid-run (e.g. reassign).
- Terminal issue guard: ClaimTaskForRuntime auto-cancels pending tasks
for done/cancelled issues instead of executing them.
- Race condition safety net: unique partial index ensures at most one
pending task per issue at the DB level.
Inbox items were previously queried only by recipient, which leaked data
across workspaces. All list/count/batch operations now filter by
workspace_id from the X-Workspace-ID header.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add an `instructions` text field to the agent model, allowing users to
define each agent's role, expertise, and working style. Instructions are
injected into CLAUDE.md as an "Agent Identity" section so the agent
knows who it is on every task execution.
- Migration 021: add instructions column to agent table
- Backend: create/update/get agent handlers support instructions
- ClaimTask response includes instructions for daemon injection
- execenv: inject instructions into CLAUDE.md meta-skill
- Frontend: add Instructions tab to agent detail panel
Store the Claude Code session ID and working directory when a task
completes. On the next task for the same (agent, issue) pair, look up
the prior session and pass --resume <session_id> to Claude Code so
the agent retains conversation context across multiple tasks on the
same issue.
Changes:
- Migration 020: add session_id and work_dir columns to agent_task_queue
- CompleteAgentTask stores session_id and work_dir on completion
- GetLastTaskSession query retrieves prior session for (agent, issue)
- ClaimTaskByRuntime handler populates prior_session_id in response
- Daemon passes ResumeSessionID through to Claude backend Execute()
- Claude backend adds --resume flag when ResumeSessionID is set
Add per-workspace auto-incrementing issue numbers with a configurable
prefix, producing identifiers like "JIA-1" instead of truncated UUIDs.
Database:
- Add issue_prefix and issue_counter to workspace table
- Add number column to issue table with UNIQUE(workspace_id, number)
- Backfill existing issues with sequential numbers
Backend:
- Issue creation atomically increments counter in a transaction
- API responses include number and identifier fields
- Support issue lookup by identifier format (KEY-N)
- Workspace prefix auto-generated from name, customizable via API
Frontend:
- Display identifier in list rows and issue detail breadcrumb
- Add issue_prefix to Workspace type, number/identifier to Issue type
Add comprehensive data visualization to the runtime detail page:
- Daily token usage stacked area chart and daily cost bar chart
- Model distribution donut chart with cost breakdown
- GitHub-style activity heatmap (13 weeks of daily token usage)
- Hourly task distribution bar chart with new backend endpoint
- Responsive 2-column grid layout for charts on wide screens
Backend: new GET /api/runtimes/{runtimeId}/activity endpoint
returning hourly task counts from agent_task_queue.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The only path to marking a runtime offline was the daemon's deregister
call on graceful shutdown. If the daemon crashed, was killed, or lost
network, the status stayed "online" forever. Add a background goroutine
that sweeps every 30s and marks runtimes offline after 45s without a
heartbeat (3 missed intervals).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add missing notifications for priority_changed and due_date_changed events
- Publish priority_changed and due_date_changed flags from UpdateIssue handler
- Add details JSONB column to inbox_item (migration 019) for structured change data
- Store from/to values in details for status, priority, assignee, and due_date changes
- Notification titles now use plain issue title; details carry structured context
- Add human-readable label maps (statusLabels, priorityLabels) in notification listeners
- Update inbox handler responses to include details field
- Frontend: InboxDetailLabel renders rich subtitles per notification type
- Status: "Set status to ● In Progress" with StatusIcon
- Priority: "Set priority to ◆ High" with PriorityIcon
- Assigned: "Assigned to Bob" with resolved actor name
- Due date: "Set due date to Apr 20"
- Comment: truncated comment body preview
- Frontend: HoverCard on inbox items shows issue title + description context
- Add due_date_changed to InboxItemType and typeLabels
- Add tests for priority_changed and due_date_changed notifications
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract shared timeAgo utility, remove duplicates from comment-card and issue-detail
- Remove unused replies prop from CommentCard
- Fix recursive delete to remove all descendant replies, not just direct children
- Improve formatActivity with human-readable status/priority labels and actor names
- Validate parent comment exists and belongs to same issue before creating reply
- Add priority_changed activity recording in activity listeners
- Fix activity SQL query to sort ASC (was DESC, then re-sorted in handler)
- Fix reply-input layout alignment and test submit button selector
- Minor: .gitignore additions, button dark mode aria-expanded fix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the comment-only list with a Linear-style unified timeline that
interleaves field changes and comments chronologically.
Backend:
- activity_listeners.go: records field changes (status, assignee, description,
task completed/failed) to activity_log table on domain events
- Timeline API: GET /api/issues/{id}/timeline merges activity_log + comments
sorted by created_at
- Comment reply: parent_id column + handler support for threading
Frontend:
- Unified timeline replaces comment list: activity entries as compact muted
lines, comments as Card components with reply threading
- Filter toggle (All / Comments / Activity)
- Reply UI: inline editor under comments with Cancel/Reply buttons
- Real-time sync for activity:created + comment events
- 10 new Go tests, all passing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace inbox_listeners.go with a subscriber-driven notification system:
- Add issue_subscriber table with auto-subscribe on create/assign/comment
- New subscriber_listeners.go: maintains subscriber data on domain events
- New notification_listeners.go: notifySubscribers (fanout to all subscribers
minus actor) and notifyDirect (targeted, punches through unsubscribe)
- Subscriber API: list/subscribe/unsubscribe endpoints
- Frontend: subscribers section in issue detail sidebar with real-time sync
- Frontend: inbox notification grouping by (issue_id, type, actor_id)
- Remove createInboxForIssueCreator from task.go (unified through event bus)
- 21 new Go tests, all passing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add a `repos` JSONB column to the workspace table for storing
associated repository URLs and descriptions. This enables the daemon
to clone repos and set up git worktrees for agent task execution.
Structure: [{"url": "https://github.com/org/repo", "description": "..."}]
- Migration 014: adds repos column with default '[]'
- UpdateWorkspace query: supports updating repos
- Workspace API: returns repos in GET, accepts in PUT
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These fields were unused in practice. Removed from frontend types,
issue detail UI, backend handlers, daemon prompt/context, protocol
messages, SQL queries, and tests. DB columns retained with defaults.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adapt runtime features (usage tracking, ping, heartbeat) to main's
multi-workspace architecture. Update frontend imports from @multica/types
to @/shared/types after the package consolidation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a new "Runtimes" sidebar tab to manage local agent runtimes with three
main capabilities: runtime status overview, token usage tracking (reading
Claude Code and Codex CLI local JSONL logs via daemon), and an interactive
connection test that sends a ping through the daemon to verify end-to-end
agent CLI connectivity.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add drag-to-resize sidebar with localStorage persistence
- Rewrite issue detail page with Tiptap rich text editor, due date picker, acceptance criteria
- Redesign create-issue modal with pill-based property toolbar and expand/collapse
- Consolidate @multica/sdk and @multica/types into apps/web/shared/
- Simplify auth: remove verification codes, PATs, email service (dev-only login)
- Add 401 unauthorized handler to redirect expired sessions to login
- Fix due date format to send full RFC3339 timestamps
- Increase description editor debounce to 1500ms
- Remove arbitrary Tailwind values in create-issue modal
- Renumber migrations (inbox_actor 012→009), remove unused migrations
- UI polish across agents, settings, inbox, knowledge-base pages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(auth): add email verification login flow with 401 auto-redirect
Replace the old OAuth-based login with email verification codes:
- Backend: send-code / verify-code endpoints, verification_codes table (migration 009), rate limiting, Resend email service
- Frontend: two-step login UI (email → 6-digit OTP), auth store with sendCode/verifyCode
- SDK: ApiClient gains onUnauthorized callback; 401 responses auto-clear token and redirect to /login
- Fix login button staying disabled due to global isLoading state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(auth): add brute-force protection, redirect loop guard, and expired code cleanup
- VerifyCode: increment attempts on wrong code, reject after 5 failed tries (migration 010)
- onUnauthorized: skip redirect if already on /login to prevent infinite loops
- SendCode: best-effort cleanup of expired verification codes older than 1 hour
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(auth): add master verification code for non-production environments
Allow code "888888" to bypass email verification in non-production
environments to simplify development and testing workflows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(auth): add personal access tokens for CLI and API authentication
Add full-stack PAT support: users create tokens in Settings, CLI authenticates
via `multica auth login`. Server stores SHA-256 hashes only. Auth middleware
extended to accept both JWTs and PATs (distinguished by `mul_` prefix).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add actor_type/actor_id to inbox items for proper attribution
- Extract issue detail into features/issues/components/issue-detail.tsx
- Inbox page and store updates for actor-based notifications
- Sidebar, layout, and actor-avatar refinements
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace agent.skills TEXT field with structured skill/skill_file/agent_skill
tables. Skills are workspace-level entities with supporting files, reusable
across agents via many-to-many bindings.
Backend: migration 008, sqlc queries, CRUD handler, agent-skill junction,
structured skill loading in task context snapshot.
Daemon: meta skill injection via runtime-native config (.claude/CLAUDE.md
for Claude, AGENTS.md for Codex) so agents discover .agent_context/ skills
through their native mechanism. Lean prompt without inlined skill content.
Frontend: Skills management page, agent Skills tab picker, SDK methods,
TypeScript types, workspace store integration.
Also removes auto-creation of init issues when creating agents.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The repository JSONB column on the issue table is unused. This removes
it end-to-end: migration to drop the column, sqlc queries, Go handler/
service/daemon/protocol structs, TypeScript types, and the
RepositoryEditor UI component.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a `context` text field to workspaces, allowing users to provide
background information and context for AI agents working in the
workspace. Full stack: migration, sqlc queries, Go handler, TS types,
SDK, and settings page UI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add UpdateComment and DeleteComment handlers with /api/comments/{commentId} routes
- Add broadcast for comment create/update/delete WebSocket events
- Support status, priority, and assignee_id filters on ListIssues
- Extend UpdateIssue to handle due_date, acceptance_criteria, context_refs, repository
- Properly distinguish "field not sent" vs "field sent as null" in UpdateIssue
- Add corresponding SDK methods and TypeScript types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add HTTP handlers for issues, comments, agents, workspaces, inbox, members, and activity
- Implement JWT authentication middleware with Bearer token validation
- Add sqlc queries for all entities (CRUD operations)
- Extract router into reusable NewRouter() for testability
- Expand SDK with full API client methods (CRUD for all resources)
- Add updateWorkspace to SDK, add Member type to shared types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>