feat(preview): inspect mode with pin and area annotations (#917)
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
```
|
||||
apps/
|
||||
├── backend/ # Go backend (orchestrator, agent runtime, agentctl, WS gateway)
|
||||
├── backend/ # Go backend (orchestrator, lifecycle, agentctl, WS gateway)
|
||||
├── web/ # Next.js frontend (SSR + WS + Zustand)
|
||||
├── cli/ # CLI tool (TypeScript)
|
||||
├── landing/ # Landing page
|
||||
@@ -21,7 +21,6 @@ apps/
|
||||
- **UI**: Shadcn components via `@kandev/ui`
|
||||
- **GitHub repo**: `https://github.com/kdlbs/kandev`
|
||||
- **Container image**: `ghcr.io/kdlbs/kandev` (GitHub Container Registry)
|
||||
- **Dev mock providers**: In `KANDEV_MOCK_AGENT=true` dev mode the base `mock-agent` is enabled alongside the real CLIs. To exercise the office provider-routing UI without installing real CLIs, set `KANDEV_MOCK_PROVIDERS=claude-acp,codex-acp,opencode-acp` (or any subset of `RoutableProviderIDs`) when launching `make dev` — those canonicals are then replaced with MockAgent aliases.
|
||||
|
||||
### Worktrees and commit hooks
|
||||
|
||||
@@ -29,275 +28,15 @@ The commit-msg hook runs `cd apps && pnpm exec commitlint --edit "$1"`. A fresh
|
||||
|
||||
---
|
||||
|
||||
## Backend Architecture
|
||||
## Scoped guidance
|
||||
|
||||
### Package Structure
|
||||
Architecture notes and per-area conventions live alongside the code they describe. Read the file in the directory you're working in:
|
||||
|
||||
```
|
||||
apps/backend/
|
||||
├── cmd/
|
||||
│ ├── kandev/ # Main backend binary entry point
|
||||
│ ├── agentctl/ # Agentctl binary (runs inside containers or standalone)
|
||||
│ └── mock-agent/ # Mock agent for testing
|
||||
├── internal/
|
||||
│ ├── agent/
|
||||
│ │ ├── runtime/ # Agent runtime: single seam for Launch/Resume/Stop/observe
|
||||
│ │ │ ├── lifecycle/ # Agent instance management (moved from agent/lifecycle)
|
||||
│ │ │ ├── agentctl/ # HTTP client for talking to agentctl (moved from agentctl/client)
|
||||
│ │ │ └── routingerr/ # Provider error classifier + sanitizer + ProviderProber registry
|
||||
│ │ ├── agents/ # Agent type implementations
|
||||
│ │ ├── controller/ # Agent control operations
|
||||
│ │ ├── credentials/ # Agent credential management
|
||||
│ │ ├── discovery/ # Agent discovery
|
||||
│ │ ├── docker/ # Docker-specific agent logic
|
||||
│ │ ├── dto/ # Agent data transfer objects
|
||||
│ │ ├── executor/ # Executor types, checks, and service
|
||||
│ │ ├── handlers/ # Agent event handlers
|
||||
│ │ ├── registry/ # Agent type registry and defaults
|
||||
│ │ ├── settings/ # Agent settings
|
||||
│ │ ├── mcpconfig/ # MCP server configuration
|
||||
│ │ └── remoteauth/ # Remote auth catalog and method IDs for remote executors/UI
|
||||
│ ├── agentctl/
|
||||
│ │ └── server/ # agentctl HTTP server
|
||||
│ │ ├── acp/ # ACP protocol implementation
|
||||
│ │ ├── adapter/ # Protocol adapters + transport/ (ACP, Codex, OpenCode, Copilot, Amp)
|
||||
│ │ ├── api/ # HTTP endpoints
|
||||
│ │ ├── config/ # agentctl configuration
|
||||
│ │ ├── instance/ # Multi-instance management
|
||||
│ │ ├── mcp/ # MCP server integration
|
||||
│ │ ├── process/ # Agent subprocess management
|
||||
│ │ ├── shell/ # Shell session management
|
||||
│ │ └── utility/ # agentctl utilities
|
||||
│ ├── orchestrator/ # Task execution coordination
|
||||
│ │ ├── dto/ # Orchestrator data transfer objects
|
||||
│ │ ├── executor/ # Launches agents via lifecycle manager
|
||||
│ │ ├── handlers/ # Orchestrator event handlers
|
||||
│ │ ├── messagequeue/ # Message queue for agent prompts
|
||||
│ │ ├── queue/ # Task queue
|
||||
│ │ ├── scheduler/ # Task scheduling
|
||||
│ │ └── watcher/ # Event handlers
|
||||
│ ├── task/
|
||||
│ │ ├── controller/ # Task HTTP/WS controllers
|
||||
│ │ ├── dto/ # Task data transfer objects
|
||||
│ │ ├── events/ # Task event types
|
||||
│ │ ├── handlers/ # Task event handlers
|
||||
│ │ ├── models/ # Task, Session, Executor, Message models
|
||||
│ │ ├── repository/ # Database access (SQLite)
|
||||
│ │ ├── service/ # Task business logic
|
||||
│ │ └── share/ # Public share links: snapshot builder, gist backend, service, redaction
|
||||
│ ├── office/ # Autonomous agent management (Office feature)
|
||||
│ │ ├── agents/ # Agent instance CRUD + auth guards
|
||||
│ │ ├── approvals/ # Approval requests and decisions
|
||||
│ │ ├── channels/ # External integration channels (webhooks)
|
||||
│ │ ├── config/ # Config sync (DB ↔ filesystem)
|
||||
│ │ ├── configloader/ # Filesystem config reader/writer
|
||||
│ │ ├── costs/ # Cost tracking and budget policies
|
||||
│ │ ├── dashboard/ # Dashboard API, issues, activity, live runs
|
||||
│ │ ├── infra/ # GC, reconciliation
|
||||
│ │ ├── labels/ # Task labels
|
||||
│ │ ├── onboarding/ # Workspace onboarding wizard API
|
||||
│ │ ├── projects/ # Project management
|
||||
│ │ ├── repository/ # Office SQLite persistence
|
||||
│ │ ├── runtime/ # Agent run context, capabilities, and runtime action surface
|
||||
│ │ ├── routines/ # Scheduled recurring tasks
|
||||
│ │ ├── routing/ # Provider routing: resolver, validators, catalogue, backoff, agent-overrides
|
||||
│ │ ├── scheduler/ # Wakeup scheduler (duplicate of service scheduler features)
|
||||
│ │ ├── service/ # Core office service (wakeups, event subscribers, execution policy)
|
||||
│ │ ├── shared/ # Shared interfaces and activity logging
|
||||
│ │ ├── skills/ # Skill injection and materialization
|
||||
│ │ └── workspaces/ # Workspace deletion handler
|
||||
│ ├── events/ # Event bus for internal pub/sub
|
||||
│ ├── gateway/ # WebSocket gateway
|
||||
│ ├── github/ # GitHub API integration (PRs, reviews, webhooks)
|
||||
│ ├── gitlab/ # GitLab API integration (MRs, discussions, pipelines)
|
||||
│ ├── common/ # Shared utilities, config, logger
|
||||
│ ├── integration/ # External integrations
|
||||
│ ├── integrations/ # Shared shapes for third-party integrations
|
||||
│ │ ├── healthpoll/ # Reusable 90s auth-health Poller (used by jira, linear)
|
||||
│ │ └── secretadapter/ # Upsert-style adapter over secrets.SecretStore
|
||||
│ ├── jira/ # Jira/Atlassian Cloud integration (config, REST client, poller)
|
||||
│ ├── linear/ # Linear integration (config, GraphQL client, poller)
|
||||
│ ├── lsp/ # LSP server
|
||||
│ ├── mcp/ # MCP protocol support
|
||||
│ ├── health/ # Health check endpoints
|
||||
│ ├── notifications/ # Notification system
|
||||
│ ├── persistence/ # Persistence layer
|
||||
│ ├── prompts/ # Prompt management
|
||||
│ ├── repoclone/ # Repository cloning for remote executors
|
||||
│ ├── scriptengine/ # Script placeholder resolution and interpolation
|
||||
│ ├── secrets/ # Secret management
|
||||
│ ├── sprites/ # Sprites AI integration
|
||||
│ ├── sysprompt/ # System prompt injection
|
||||
│ ├── task/
|
||||
│ │ └── ...
|
||||
│ ├── tools/ # Tool integrations
|
||||
│ ├── user/ # User management
|
||||
│ ├── utility/ # Shared utility functions
|
||||
│ ├── workflow/ # Workflow engine
|
||||
│ │ ├── engine/ # Typed state-machine engine
|
||||
│ │ ├── models/ # Workflow step, template, and history models
|
||||
│ │ ├── repository/ # Workflow persistence (SQLite)
|
||||
│ │ └── service/ # Workflow CRUD and step resolution
|
||||
│ └── worktree/ # Git worktree management for workspace isolation
|
||||
```
|
||||
|
||||
### Key Concepts
|
||||
|
||||
**Orchestrator** coordinates task execution:
|
||||
- Receives task start/stop/resume requests via WebSocket
|
||||
- Delegates to lifecycle manager for agent operations
|
||||
- Handles event-driven state transitions via workflow engine
|
||||
- Located in `internal/orchestrator/`
|
||||
|
||||
**Workflow Engine** (`internal/workflow/engine/`) provides typed state-machine evaluation:
|
||||
- `Engine.HandleTrigger()` evaluates step actions for triggers (on_enter, on_turn_start, on_turn_complete, on_exit)
|
||||
- `TransitionStore` interface abstracts persistence (implemented by `orchestrator.workflowStore`)
|
||||
- `CallbackRegistry` maps action kinds to callbacks (plan mode, auto-start, context reset)
|
||||
- First-transition-wins: multiple transition actions in one trigger, first eligible wins
|
||||
- `EvaluateOnly` mode: engine evaluates without persisting, caller orchestrates on_exit → DB → on_enter
|
||||
- `RequiresApproval` on actions: transitions requiring review gating are skipped
|
||||
- Idempotent by `OperationID`; session-scoped data bag via `MachineState.Data`
|
||||
|
||||
**Agent Runtime** (`internal/agent/runtime/`) is the single seam for launching, resuming, stopping, and observing agent executions. ADR 0004 introduced this in Phase 1 of task-model-unification. The public surface is `runtime.Runtime` (`runtime.go`); a thin facade (`facade.go`) delegates to a `Backend` (satisfied by `*lifecycle.Manager`).
|
||||
|
||||
**Convention:** only `internal/agent/runtime/` (and code that pre-dates Phase 1 migration) may import `runtime/lifecycle` or `runtime/agentctl` directly. New consumers — workflow engine actions, cron-driven trigger handlers, future task-tier callers — should depend on `runtime.Runtime`. Existing call sites are migrated through later phases of task-model-unification.
|
||||
|
||||
**Lifecycle Manager** (`internal/agent/runtime/lifecycle/`) manages agent instances under the runtime:
|
||||
- `Manager` (`manager.go`, `manager_*.go`) - central coordinator for agent lifecycle
|
||||
- `ExecutorBackend` interface (`executor_backend.go`) - abstracts execution environment (Docker, Standalone, Sprites, Remote Docker)
|
||||
- `ExecutionStore` (`execution_store.go`) - thread-safe in-memory execution tracking
|
||||
- `session.go` - ACP session initialization and resume
|
||||
- `streams.go` - WebSocket stream connections to agentctl
|
||||
- `process_runner.go` - agent process launch and management
|
||||
- `profile_resolver.go` - resolves agent profiles/settings
|
||||
|
||||
**agentctl client** (`internal/agent/runtime/agentctl/`) is the HTTP/WS client used by the lifecycle manager to talk to a running agentctl instance. It is a runtime-tier package and should not be imported outside `internal/agent/runtime/`.
|
||||
|
||||
**agentctl** is an HTTP server that:
|
||||
- Runs inside Docker containers or as standalone process
|
||||
- Manages agent subprocess via stdin/stdout (ACP protocol)
|
||||
- Exposes workspace operations (shell, git, files)
|
||||
- Supports multiple concurrent instances on different ports
|
||||
|
||||
**Executor Types** (database model):
|
||||
- `local_pc` - Standalone process on host ✅
|
||||
- `local_docker` - Docker container on host ✅
|
||||
- `sprites` - Sprites cloud environment ✅
|
||||
- `remote_docker`, `remote_vps`, `k8s` - Planned
|
||||
|
||||
### Execution Flow
|
||||
|
||||
```
|
||||
Client (WS) → Orchestrator → Lifecycle Manager → ExecutorBackend (container/process) → agentctl
|
||||
↓
|
||||
Client (WS) ← Orchestrator ← Lifecycle Manager ←──── stream updates (WS) ──────── agent subprocess
|
||||
```
|
||||
|
||||
1. Orchestrator receives `session.launch` via WS
|
||||
2. Lifecycle Manager creates executor instance (container or process)
|
||||
3. agentctl starts inside the instance, agent subprocess is configured and started
|
||||
4. Agent events stream back via WS through the chain
|
||||
|
||||
**Session Resume:** `TaskSession.ACPSessionID` stored for resume; `ExecutorRunning` tracks active state; on restart `RecoverInstances()` reconnects.
|
||||
|
||||
**Provider Pattern:** Packages expose `Provide(cfg, log) (*impl, cleanup, error)` for DI. Returns implementation, cleanup function, and error. Cleanup called during graceful shutdown.
|
||||
|
||||
**Worktrees:** `internal/worktree/Manager` provides workspace isolation. Each session can have its own worktree (branch) to prevent conflicts between concurrent agents.
|
||||
|
||||
**Executor default scripts:** Default prepare scripts are in `internal/agent/runtime/lifecycle/default_scripts.go`; `internal/scriptengine/` handles placeholder resolution.
|
||||
|
||||
---
|
||||
|
||||
## agentctl Server
|
||||
|
||||
### API Groups
|
||||
|
||||
agentctl exposes these route groups (see `internal/agentctl/server/api/`):
|
||||
- `/health`, `/info`, `/status` - Health and status
|
||||
- `/instances/*` - Multi-instance management
|
||||
- `/processes/*` - Agent subprocess management (start/stop)
|
||||
- `/agent/configure`, `/agent/stream` - Agent configuration and event streaming
|
||||
- `/git/*` - Git operations (status, commit, push, pull, rebase, stage, etc.)
|
||||
- `/shell/*` - Shell session management
|
||||
- `/workspace/*` - File operations, search, tree
|
||||
- `/vscode/*` - VS Code integration proxy
|
||||
|
||||
### Adapter Model
|
||||
|
||||
Protocol adapters in `adapter/transport/` normalize different agent CLIs:
|
||||
- `AgentAdapter` interface defines `Start()`, `Stop()`, `Prompt()`, `Cancel()`
|
||||
- Transports: `acp` (Claude Code), `codex` (OpenAI Codex), `opencode`, `shared`, `streamjson`
|
||||
- Top-level adapters: `CopilotAdapter` (GitHub Copilot SDK), `AmpAdapter` (Sourcegraph Amp)
|
||||
- `process.Manager` owns subprocess, wires stdio to adapter
|
||||
- Factory pattern in `adapter/factory.go` selects adapter by agent type
|
||||
|
||||
### ACP Protocol
|
||||
|
||||
JSON-RPC 2.0 over stdin/stdout between agentctl and agent process. Requests: `initialize`, `session/new`, `session/load`, `session/prompt`, `session/cancel`. Notifications: `session/update` with types `message_chunk`, `tool_call`, `tool_update`, `complete`, `error`, `permission_request`, `context_window`.
|
||||
|
||||
---
|
||||
|
||||
## Frontend Architecture
|
||||
|
||||
### UI Components
|
||||
|
||||
**Shadcn Components:** Import from `@kandev/ui` package:
|
||||
```typescript
|
||||
import { Badge } from '@kandev/ui/badge';
|
||||
import { Button } from '@kandev/ui/button';
|
||||
import { Dialog } from '@kandev/ui/dialog';
|
||||
// etc...
|
||||
```
|
||||
|
||||
**Do NOT** import from `@/components/ui/*` - always use `@kandev/ui` package.
|
||||
|
||||
### Data Flow Pattern (Critical)
|
||||
|
||||
```
|
||||
SSR Fetch -> Hydrate Store -> Components Read Store -> Hooks Subscribe
|
||||
```
|
||||
|
||||
**Never fetch data directly in components.**
|
||||
|
||||
### Store Structure (Domain Slices)
|
||||
|
||||
```
|
||||
lib/state/
|
||||
├── store.ts # Root composition
|
||||
├── default-state.ts # Default state + initial state merge
|
||||
├── slices/ # Domain slices
|
||||
│ ├── kanban/ # boards, tasks, columns
|
||||
│ ├── session/ # sessions, messages, turns, worktrees
|
||||
│ ├── session-runtime/ # shell, processes, git, context
|
||||
│ ├── workspace/ # workspaces, repos, branches
|
||||
│ ├── settings/ # executors, agents, editors, prompts (incl. userSettings)
|
||||
│ ├── office/ # office agents, skills, projects, dashboard, issues
|
||||
│ ├── comments/ # code review diff comments
|
||||
│ ├── github/ # GitHub PRs, reviews
|
||||
│ └── ui/ # preview, connection, active state, sidebar views
|
||||
├── hydration/ # SSR merge strategies
|
||||
|
||||
hooks/domains/{kanban,session,workspace,settings,comments,github}/ # Domain-organized hooks
|
||||
lib/api/domains/ # API clients
|
||||
├── kanban-api, session-api, workspace-api, settings-api, process-api
|
||||
├── plan-api, queue-api, workflow-api, stats-api, github-api
|
||||
├── office-api, office-extended-api, tree-api
|
||||
├── user-shell-api, debug-api, secrets-api, sprites-api, vscode-api
|
||||
├── health-api, utility-api
|
||||
```
|
||||
|
||||
**Key State Paths:**
|
||||
- `messages.bySession[sessionId]`, `shell.outputs[sessionId]`, `gitStatus.bySessionId[sessionId]`
|
||||
- `tasks.activeTaskId`, `tasks.activeSessionId`, `workspaces.activeId`
|
||||
- `repositories.byWorkspace`, `repositoryBranches.byRepository`
|
||||
|
||||
**Hydration:** `lib/state/hydration/merge-strategies.ts` has `deepMerge()`, `mergeSessionMap()`, `mergeLoadingState()` to avoid overwriting live client state. Pass `activeSessionId` to protect active sessions.
|
||||
|
||||
**Hooks Pattern:** Hooks in `hooks/domains/` encapsulate WS subscription + store selection. WS client deduplicates subscriptions automatically.
|
||||
|
||||
### WS
|
||||
|
||||
**Format:** `{id, type, action, payload, timestamp}`.
|
||||
- `apps/backend/AGENTS.md` — Go backend: package structure (incl. `internal/office/` and `internal/agent/runtime/`), key concepts (orchestrator, workflow engine, agent runtime, lifecycle manager), execution flow, provider pattern, backups, testing conventions, Go lint limits.
|
||||
- `apps/backend/internal/agentctl/AGENTS.md` — agentctl HTTP server: route groups, adapter model, ACP protocol.
|
||||
- `apps/backend/internal/agentctl/server/api/AGENTS.md` — reverse-proxy body rewriting (`Accept-Encoding`), iframe-blocking header stripping.
|
||||
- `apps/backend/internal/integrations/AGENTS.md` — adding a new third-party integration (Jira/Linear pattern, both backend and frontend halves). The `/add-integration` skill mirrors this for scaffolding new integrations.
|
||||
- `apps/web/AGENTS.md` — Next.js frontend: shadcn imports, SSR-hydrate-store data flow, store slice structure (incl. `office`), WS format, component conventions, TS lint limits.
|
||||
|
||||
---
|
||||
|
||||
@@ -305,30 +44,22 @@ lib/api/domains/ # API clients
|
||||
|
||||
### Commit Conventions (enforced by CI)
|
||||
|
||||
Commits to `main` **must** follow [Conventional Commits](https://www.conventionalcommits.org/) (`type: description`). PRs are squash-merged — the PR title becomes the commit, validated by CI. Changelog is auto-generated from these via git-cliff (`cliff.toml`). See `.agents/skills/commit/SKILL.md` for allowed types and examples.
|
||||
Commits to `main` **must** follow [Conventional Commits](https://www.conventionalcommits.org/) (`type: description`). PRs are squash-merged - the PR title becomes the commit, validated by CI. Changelog is auto-generated from these via git-cliff (`cliff.toml`). See `.agents/skills/commit/SKILL.md` for allowed types and examples.
|
||||
|
||||
The commitlint hook caps the header at **100 characters** (`type(scope): description`). The pre-commit prettier hook also reformats staged TS/TSX files - if it does, the commit fails. Re-stage the reformatted files and create a new commit (don't `--amend`).
|
||||
|
||||
### Release & Versioning
|
||||
|
||||
Kandev uses a **single SemVer** `X.Y.Z` across npm, Homebrew, and GitHub release; release flow runs entirely in CI via `.github/workflows/release.yml`. Full details in the `/release` skill — load it when cutting a release or debugging release artifacts.
|
||||
|
||||
### Code Quality (enforced by linters)
|
||||
### Code Quality
|
||||
|
||||
Static analysis runs in CI and pre-commit. New code **must** stay within these limits:
|
||||
Static analysis runs in CI and pre-commit. Each subtree has its own thresholds:
|
||||
|
||||
**Go** (`apps/backend/.golangci.yml` - errors on new code only):
|
||||
- Functions: **≤80 lines**, **≤50 statements**
|
||||
- Cyclomatic complexity: **≤15** · Cognitive complexity: **≤30**
|
||||
- Nesting depth: **≤5** · Naked returns only in functions **≤30 lines**
|
||||
- No duplicated blocks (**≥150 tokens**) · Repeated strings → constants (**≥3 occurrences**)
|
||||
- Go limits: see `apps/backend/AGENTS.md` (and `apps/backend/.golangci.yml`).
|
||||
- TypeScript limits: see `apps/web/AGENTS.md` (and `apps/web/eslint.config.mjs`).
|
||||
|
||||
**TypeScript** (`apps/web/eslint.config.mjs` - warnings, will become errors):
|
||||
- Files: **≤600 lines** · Functions: **≤100 lines**
|
||||
- Cyclomatic complexity: **≤15** · Cognitive complexity: **≤20**
|
||||
- Nesting depth: **≤4** · Parameters: **≤5**
|
||||
- No duplicated strings (**≥4 occurrences**) · No identical functions · No unused imports
|
||||
- No nested ternaries
|
||||
|
||||
**When you hit a limit:** extract a helper function, custom hook, or sub-component. Prefer composition over growing a single function.
|
||||
When you hit a limit: extract a helper function, custom hook, or sub-component. Prefer composition over growing a single function.
|
||||
|
||||
### Testing
|
||||
|
||||
@@ -339,34 +70,6 @@ Every code change must include tests for new or changed logic. Backend: `*_test.
|
||||
- **Decisions:** Architecture decisions are recorded in `docs/decisions/`. Read `docs/decisions/INDEX.md` for an overview. When making significant architectural choices, create a new ADR via `/record decision`.
|
||||
- **Plans:** Implementation plans are generated from specs via `/plan` and saved to `docs/specs/<slug>/plan.md`. Plans are gitignored (working files, not committed) — only specs and ADRs are tracked.
|
||||
|
||||
### Backend
|
||||
- Provider pattern for DI; stderr for logs, stdout for ACP only
|
||||
- Pass context through chains; event bus for cross-component comm
|
||||
- **Execution access:** Workspace-oriented handlers (files, shell, inference, ports, vscode, LSP) MUST use `GetOrEnsureExecution(ctx, sessionID)` — it recovers from backend restarts by creating executions on-demand. Only use `GetExecutionBySessionID` for operations that require a running agent process (prompt, cancel, mode).
|
||||
- **Task lifecycle events:** Any code path that mutates a task row must publish via the event bus (`task.created` / `task.updated` / `task.deleted`) — either by going through `Service.CreateTask` / `UpdateTask` / `DeleteTask` / `ArchiveTask`, or by calling `publishTaskEvent` (or one of the `Publish*` helpers in `service_events.go`) directly. Walking `repository.TaskRepository` straight bypasses event publishing and breaks WS-driven UI like the All-Workflows kanban view. `HandoffService`'s cascade methods learned this the hard way — they now require a `TaskEventPublisher` wired via `SetTaskEventPublisher`. New cascade / bulk / cleanup paths must follow the same pattern.
|
||||
- **Testing:** Prefer `testing/synctest` (Go 1.24+) over `time.Sleep` for time-dependent tests. Use `synctest.Test` to wrap tests with tickers or timeouts — it advances fake time instantly when all goroutines are idle. When `synctest` is not feasible (e.g., tests spawning external processes like `git`), use channel-based synchronization (`<-started`, non-blocking `select`) instead of sleep-based waits. Reserve `time.Sleep` only for integration tests that need real subprocess execution time.
|
||||
|
||||
### Backups
|
||||
- On every SQLite boot, `persistence.Provide` reads `kandev_meta.kandev_version`. If the stored version differs from the binary version (or any user tables exist but no version is recorded), it takes a `VACUUM INTO` snapshot into `<data-dir>/backups/` before running migrations.
|
||||
- Retention: 2 backups kept (newest two by mtime); older ones are pruned after the snapshot succeeds.
|
||||
- Postgres: backup is skipped with a log line. Use `pg_dump` for Postgres backups.
|
||||
- Boot aborts if the backup fails -- the pool is closed and `Provide` returns an error.
|
||||
- After all repos complete `initSchema`, `cmd/kandev/storage.go:recordSchemaVersion` writes the current binary version into `kandev_meta` (non-fatal; a failure just means the next boot will take a fresh snapshot).
|
||||
- Migration logging: `db.MigrateLogger.Apply(name, stmt)` -- success logs Info, "already exists"/"duplicate column name" is silently swallowed, anything else logs Warn but never returns an error (preserving the existing swallow-error contract).
|
||||
|
||||
### Frontend
|
||||
- **Data:** SSR fetch → hydrate → read store. Never fetch in components
|
||||
- **UI Components:**
|
||||
- Import shadcn components from `@kandev/ui`, NOT `@/components/ui/*`
|
||||
- **Always prefer native shadcn components** over custom implementations
|
||||
- Check `apps/packages/ui/src/` for available components (pagination, table, dialog, etc.)
|
||||
- For data tables, use `@kandev/ui/table` with TanStack Table; use shadcn Pagination components
|
||||
- Only create custom components when shadcn doesn't provide what's needed
|
||||
- **Components:** <200 lines, extract to domain components, composition over props
|
||||
- **Hooks:** Domain-organized in `hooks/domains/`, encapsulate subscription + selection
|
||||
- **WS:** Use subscription hooks only; client auto-deduplicates
|
||||
- **Interactivity:** All buttons and links with actions must have `cursor-pointer` class
|
||||
|
||||
### Plan Implementation
|
||||
- After implementing a plan, run `make fmt` first to format code, then run `make typecheck test lint` to verify the changes. Formatting must come first because formatters may split lines, which can trigger complexity linter warnings.
|
||||
|
||||
@@ -378,7 +81,7 @@ Skills use `gh` CLI by default. If a `gh` command fails (not installed, not auth
|
||||
|
||||
### Third-party integrations
|
||||
|
||||
Jira and Linear are the model (per-workspace credentials, 90s auth-health poller via `internal/integrations/healthpoll`, settings page with status banner). New integrations should **reuse the shared shapes** rather than copying either. Full layout, file conventions, and Jira-vs-Linear divergence notes in the `/add-integration` skill — load it when scaffolding a new integration.
|
||||
Jira and Linear are the model (per-workspace credentials, 90s auth-health poller via `internal/integrations/healthpoll`, settings page with status banner). New integrations should **reuse the shared shapes** rather than copying either. Full layout, file conventions, and Jira-vs-Linear divergence notes in `apps/backend/internal/integrations/AGENTS.md` and the `/add-integration` skill — load either when scaffolding a new integration.
|
||||
|
||||
### Runtime profiles (prod / dev / e2e)
|
||||
|
||||
@@ -394,6 +97,8 @@ To flip a feature on for every user: change its `prod:` to `"true"` in `profiles
|
||||
|
||||
This file is read by AI coding agents (Claude Code via `CLAUDE.md` symlink, Codex via `AGENTS.md`). If your changes make any section of this file outdated or inaccurate - e.g., you add/remove/rename packages, change architectural patterns, add new adapters, modify store slices, or change conventions - **update the relevant sections of this file as part of the same PR**. Keep descriptions concise and factual. Do not add speculative or aspirational content.
|
||||
|
||||
When a change is scoped to a single subtree, update the scoped `AGENTS.md` instead of (or in addition to) this root file. See the "Scoped guidance" pointers at the top.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-05-16
|
||||
|
||||
Reference in New Issue
Block a user