diff --git a/.agents/skills/clean-branches/SKILL.md b/.agents/skills/clean-branches/SKILL.md new file mode 100644 index 0000000000..3769b409d8 --- /dev/null +++ b/.agents/skills/clean-branches/SKILL.md @@ -0,0 +1,42 @@ +--- +name: clean-branches +description: Delete local branches whose remote has been deleted ([gone]), including their worktrees. Use for branch cleanup after merging PRs. +--- + +# Clean Branches + +Remove local branches that have been deleted on the remote (marked `[gone]`), including any associated git worktrees. + +## Steps + +1. **Fetch and prune remote refs:** + ```bash + git fetch --prune + ``` + +2. **List branches to identify [gone] status:** + ```bash + git branch -v + ``` + Branches with a `+` prefix have associated worktrees that must be removed before deletion. + +3. **List worktrees for reference:** + ```bash + git worktree list + ``` + +4. **Remove worktrees and delete [gone] branches:** + ```bash + git branch -v | grep '\[gone\]' | sed 's/^[+* ]//' | awk '{print $1}' | while read branch; do + echo "Processing branch: $branch" + worktree=$(git worktree list | grep "\\[$branch\\]" | awk '{print $1}') + if [ ! -z "$worktree" ] && [ "$worktree" != "$(git rev-parse --show-toplevel)" ]; then + echo " Removing worktree: $worktree" + git worktree remove --force "$worktree" + fi + echo " Deleting branch: $branch" + git branch -D "$branch" + done + ``` + +5. **Report** which branches and worktrees were removed. If none were `[gone]`, say no cleanup was needed. diff --git a/.agents/skills/code-review/SKILL.md b/.agents/skills/code-review/SKILL.md new file mode 100644 index 0000000000..3e7aae8a38 --- /dev/null +++ b/.agents/skills/code-review/SKILL.md @@ -0,0 +1,66 @@ +--- +name: code-review +description: Review changed code in the Kandev monorepo for quality, security, and architecture compliance. Use after implementing features or before opening PRs. +--- + +# Code Review + +Review the current changes in the Kandev codebase (Go + Next.js monorepo). + +## Steps + +### 1. Run verification first + +Invoke the `/verify` skill to ensure all formatters, linters, typechecks, and tests pass. Do NOT proceed with review until verify passes clean. + +### 2. Identify changed files + +Run `git diff --name-only` (and `git diff --cached --name-only` for staged changes) to get the list of modified files. Read each changed file. + +### 3. Review for issues + +Check every changed file for the following. Report issues with `file_path:line_number` references. + +**Complexity limits** (these are enforced by CI — catch them early): +- Go: functions ≤80 lines, ≤50 statements, cyclomatic ≤15, cognitive ≤30, nesting ≤5 +- TS: files ≤600 lines, functions ≤100 lines, cyclomatic ≤15, cognitive ≤20, nesting ≤4 +- If a file is too large or a function too complex, split it into smaller cohesive files/functions grouped by responsibility + +**Duplicated code:** +- Look for copy-pasted logic across changed files and their surrounding code +- Extract shared helpers, constants, or utility functions when duplication is found + +**Dead code:** +- Unused functions, variables, imports, types, or unreachable branches introduced by the changes +- Remove them — don't leave commented-out code + +**Security:** +- No secrets, tokens, or credentials in code +- Proper input validation at system boundaries (user input, API handlers, external data) +- No SQL injection, XSS, command injection, or path traversal risks + +**Architecture violations:** +- Frontend: no direct data fetching in components (must go through store), shadcn imports from `@kandev/ui` not `@/components/ui/*` +- Backend: provider pattern for DI, context passed through call chains, event bus for cross-component communication + +**Missing unit tests:** +- Backend (Go): new or changed functions/methods should have corresponding tests +- Frontend (JS/TS libs only): new utility functions, hooks, API clients, and store slices should have tests +- We do NOT test React components — skip those +- Flag untested logic but don't block on it; suggest what tests to add + +**Improvements:** +- Suggest simplifications, better naming, or more idiomatic patterns — but only if the improvement is clear and worth the churn +- Don't nitpick formatting or style that linters already cover + +### 4. Fix or report + +- **Fix directly** any issues you can resolve confidently (dead code, unused imports, simple duplication, missing early returns) +- **Report with explanation** any issues that need the author's input (architectural decisions, ambiguous test coverage, design trade-offs) + +### 5. Summary + +Provide a brief summary: +- Number of issues found and fixed +- Any remaining items that need author attention +- Overall assessment: ready to merge, needs minor fixes, or needs rework diff --git a/.agents/skills/commit/SKILL.md b/.agents/skills/commit/SKILL.md index 50801750bd..030135a7fb 100644 --- a/.agents/skills/commit/SKILL.md +++ b/.agents/skills/commit/SKILL.md @@ -1,6 +1,6 @@ --- name: commit -description: Create git commits following Conventional Commits format. Use when committing changes, creating commits, or when the user asks to commit. Ensures commit messages conform to the project's changelog generation conventions. +description: Stage and commit changes using Conventional Commits. Use when there are dirty/staged files to commit, the user says "commit", or before pushing a PR. --- # Commit diff --git a/.agents/skills/pr-comments/SKILL.md b/.agents/skills/pr-comments/SKILL.md new file mode 100644 index 0000000000..3f62a0060e --- /dev/null +++ b/.agents/skills/pr-comments/SKILL.md @@ -0,0 +1,73 @@ +--- +name: pr-comments +description: Address PR review comments — fix valid ones, react with thumbs up, resolve threads, and push. +--- + +# PR Comments + +Read and address review comments on a pull request, then push fixes. + +## Context + +- Current branch: !`git branch --show-current` +- Current PR (if any): !`gh pr view --json number,url,title --jq '"\(.url) - \(.title)"' 2>/dev/null || echo "no PR found"` + +## Steps + +### 1. Fetch comments + +Get the PR number from context or the user. Fetch all review comments: + +```bash +gh pr view --json reviews,comments +gh api repos/{owner}/{repo}/pulls//comments +``` + +Also check for top-level PR comments and review threads. + +### 2. Triage each comment + +For each comment, decide: +- **Valid and actionable** — the comment points to a real issue (bug, missing edge case, naming, architecture concern, code quality). Proceed to fix it. +- **Already addressed** — the code already handles what the comment suggests. Skip it. +- **Nitpick or preference** — subjective style preference not covered by linters. Skip unless the reviewer is insistent. +- **Wrong or outdated** — the comment misunderstands the code or refers to old state. Skip it. + +### 3. Fix valid comments + +For each valid comment: +1. Read the file at the referenced line +2. Implement the fix +3. React with a thumbs up on the comment: + ```bash + gh api repos/{owner}/{repo}/pulls/comments//reactions -f content="+1" + ``` +4. Resolve the review thread: + ```bash + gh api graphql -f query='mutation { resolveReviewThread(input: {threadId: ""}) { thread { isResolved } } }' + ``` + Get the `thread_node_id` from the review threads query (use `node_id` field from the thread, not the comment ID). + +### 4. Verify + +Run `/verify` to ensure formatters, linters, typechecks, and tests all pass. Do NOT push until verify passes clean. + +### 5. Commit and push + +Run `/commit` to stage and commit the fixes. Use a message like: +``` +fix: address PR review feedback +``` +or be more specific if fixes are scoped (e.g., `fix: add nil check per review feedback`). + +Then push: +```bash +git push +``` + +### 6. Summary + +Report what was done: +- Which comments were addressed (with thumbs up) +- Which comments were skipped and why +- Link to the pushed commit diff --git a/.agents/skills/push-pr/SKILL.md b/.agents/skills/push-pr/SKILL.md new file mode 100644 index 0000000000..68976b578e --- /dev/null +++ b/.agents/skills/push-pr/SKILL.md @@ -0,0 +1,57 @@ +--- +name: push-pr +description: Push the current branch and open a draft PR. Use when the user wants to open a pull request or push their work for review. +--- + +## Context + +- Current git status: !`git status` +- Current branch: !`git branch --show-current` +- Commits on this branch vs main: !`git log --oneline main..HEAD` +- Recent commit messages for style reference: !`git log --oneline -5` + +## Your task + +Push the current branch and open a **draft** pull request. + +### Rules + +1. **Uncommitted changes:** If there are dirty or staged changes, run the `/commit` skill first to commit them before proceeding. + +2. **Branch:** If on `main`, create a new branch from the commits (use a descriptive name like `feat/short-description` or `fix/short-description`) and switch to it before pushing. If already on a feature branch, use it as-is. + +3. **Push:** Push the branch to origin with `-u` to set upstream tracking. + +4. **PR title** must follow Conventional Commits format (CI validates this via `pr-title.yml`, and it becomes the squash-merge commit used for release notes): + - Format: `type(scope): lowercase description` or `type: lowercase description` + - Allowed types: `feat`, `fix`, `perf`, `refactor`, `docs`, `chore`, `ci`, `test` + - Subject starts with a lowercase letter + - Keep under 72 characters + - Add `!` after type for breaking changes: `feat!: remove legacy API` + - Examples: `feat(ui): add task filter dialog`, `fix: prevent duplicate session on reconnect` + +5. **PR body** must follow the project's pull request template. Fill in each section using these rules: + - **Summary** (required): 1–2 sentences of prose, no heading. Lead with the problem/goal, end with the outcome. Say WHY, not what. + - **Important Changes** (optional): short bullet list of significant architectural changes. Remove section if not needed. + - **Validation** (required): list commands or checks run (e.g. `go test ./...`, `make lint`). + - **Diagram** (optional): Mermaid diagram only for non-obvious flows. Remove section if not needed. + - **Possible Improvements** (optional): one line on risk and what could go wrong. Remove section if not needed. + - **Checklist**: always include as-is, do not pre-fill. + - **Related issues**: use `Closes #N` if applicable, otherwise remove. + - Do NOT add tool attribution footers. + - Do NOT leave placeholder text or unfilled sections. + +6. **Always create as draft:** Use `gh pr create --draft`. + +7. **Execute in a single message.** Push and create the PR using parallel tool calls where possible. Do not read files or do anything else beyond what's listed here. + +### Command + +``` +gh pr create --draft --title "type: description" --body "$(cat <<'EOF' + +EOF +)" +``` + +8. **Return the PR URL** when done. diff --git a/.agents/skills/verify/SKILL.md b/.agents/skills/verify/SKILL.md new file mode 100644 index 0000000000..6bf8b4536b --- /dev/null +++ b/.agents/skills/verify/SKILL.md @@ -0,0 +1,35 @@ +--- +name: verify +description: Run format, typecheck, test, and lint across the monorepo. Use after implementing changes. +--- + +# Verify + +Run the full verification pipeline for the Kandev monorepo, then fix any issues found. + +## Steps + +1. **Format first** (prevents formatter-induced lint failures): + - `make -C apps/backend fmt` + - `cd apps && pnpm format` + +2. **Verify in parallel** where possible: + - `make -C apps/backend test lint` + - `cd apps && pnpm --filter @kandev/web typecheck && pnpm --filter @kandev/web lint` + +3. **Fix issues** — do NOT just report them: + - Read each failing file at the reported line number + - Fix the root cause (don't suppress warnings or add ignores) + - Common fixes: + - **Type errors**: fix the type, add a missing import, or correct the function signature + - **Lint — function too long**: extract a helper function or sub-component + - **Lint — file too long**: split the file into smaller, cohesive files grouped by responsibility (e.g., separate types, helpers, constants, or sub-domains into their own files) + - **Lint — cyclomatic/cognitive complexity**: simplify conditionals, extract early returns, break into smaller functions + - **Lint — unused imports**: remove them + - **Lint — duplicate strings**: extract to a constant + - **Test failures**: read the test, understand the assertion, fix the code (not the test) unless the test is outdated + - After fixing, re-run only the failed command to confirm the fix + +4. **Repeat** steps 2-3 until all commands pass. If a fix introduces new issues, address those too. + +5. **Done** when all four pass cleanly: fmt, typecheck, test, lint. diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000000..472ae7b559 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,24 @@ +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "Edit", + "hooks": [ + { + "type": "command", + "command": "f=\"$TOOL_INPUT_FILE_PATH\"; case \"$f\" in *.ts|*.tsx|*.js|*.jsx) root=$(cd \"$(dirname \"$f\")\" && git rev-parse --show-toplevel 2>/dev/null) && npx --prefix \"$root/apps\" prettier --write \"$f\" 2>/dev/null ;; *.go) gofmt -w \"$f\" 2>/dev/null ;; esac" + } + ] + }, + { + "matcher": "Write", + "hooks": [ + { + "type": "command", + "command": "f=\"$TOOL_INPUT_FILE_PATH\"; case \"$f\" in *.ts|*.tsx|*.js|*.jsx) root=$(cd \"$(dirname \"$f\")\" && git rev-parse --show-toplevel 2>/dev/null) && npx --prefix \"$root/apps\" prettier --write \"$f\" 2>/dev/null ;; *.go) gofmt -w \"$f\" 2>/dev/null ;; esac" + } + ] + } + ] + } +} diff --git a/AGENTS.md b/AGENTS.md index b66682a492..3137cd9c8c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,6 +9,7 @@ apps/ ├── backend/ # Go backend (orchestrator, lifecycle, agentctl, WS gateway) ├── web/ # Next.js frontend (SSR + WS + Zustand) ├── cli/ # CLI tool (TypeScript) +├── landing/ # Landing page └── packages/ # Shared packages/types ``` @@ -42,22 +43,26 @@ apps/backend/ │ │ ├── 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 -│ │ ├── runtime/ # Runtime name constants │ │ ├── settings/ # Agent settings │ │ ├── mcpconfig/ # MCP server configuration │ │ └── remoteauth/ # Remote auth catalog and method IDs for remote executors/UI │ ├── agentctl/ │ │ ├── client/ # HTTP client for talking to agentctl │ │ └── server/ # agentctl HTTP server +│ │ ├── acp/ # ACP protocol implementation +│ │ ├── adapter/ # Protocol adapters + transport/ (ACP, Codex, OpenCode, Copilot, Amp) │ │ ├── api/ # HTTP endpoints -│ │ ├── adapter/ # Protocol adapters (ACP, Codex, Copilot, Amp) +│ │ ├── config/ # agentctl configuration │ │ ├── instance/ # Multi-instance management │ │ ├── mcp/ # MCP server integration │ │ ├── process/ # Agent subprocess management -│ │ └── shell/ # Shell session 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 @@ -84,6 +89,7 @@ apps/backend/ │ ├── integration/ # External integrations │ ├── lsp/ # LSP server │ ├── mcp/ # MCP protocol support +│ ├── health/ # Health check endpoints │ ├── notifications/ # Notification system │ ├── persistence/ # Persistence layer │ ├── prompts/ # Prompt management @@ -96,6 +102,7 @@ apps/backend/ │ │ └── ... │ ├── tools/ # Tool integrations │ ├── user/ # User management +│ ├── utility/ # Shared utility functions │ ├── workflow/ # Workflow engine │ │ ├── engine/ # Typed state-machine engine (trigger evaluation, action callbacks, transition store) │ │ ├── models/ # Workflow step, template, and history models @@ -122,13 +129,11 @@ apps/backend/ - Idempotent by `OperationID`; session-scoped data bag via `MachineState.Data` **Lifecycle Manager** (`internal/agent/lifecycle/`) manages agent instances: -- `Manager` (`manager.go`) - central coordinator for agent lifecycle -- `Runtime` interface (`runtime.go`) - abstracts execution environment (Docker, Standalone, Remote Docker) +- `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 -- `events.go` - publishes events to the event bus -- `container.go` - Docker container operations - `process_runner.go` - agent process launch and management - `profile_resolver.go` - resolves agent profiles/settings @@ -141,43 +146,23 @@ apps/backend/ **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 -**Runtime Interface** implements execution: -```go -type Runtime interface { - Name() runtime.Name - HealthCheck(ctx context.Context) error - CreateInstance(ctx context.Context, req *RuntimeCreateRequest) (*RuntimeInstance, error) - StopInstance(ctx context.Context, instance *RuntimeInstance, force bool) error - RecoverInstances(ctx context.Context) ([]*RuntimeInstance, error) -} -``` - ### Execution Flow ``` -Client (WS) Orchestrator Lifecycle Manager Runtime agentctl - | | | | | - | task.start | | | | - |--------------->| LaunchAgent() | | | - | |--------------------->| CreateInstance() | | - | | |----------------->| (container) | - | | | |--------------->| - | | StartAgentProcess() | | | - | |--------------------->| ConfigureAgent() | | - | | |-----------------------------> | - | | | Start() | | - | | |-----------------------------> | - | | | | agent proc | - | | |<---- stream updates (WS) ---------| - |<--- WS events -| | | | +Client (WS) → Orchestrator → Lifecycle Manager → ExecutorBackend (container/process) → agentctl + ↓ +Client (WS) ← Orchestrator ← Lifecycle Manager ←──── stream updates (WS) ──────── agent subprocess ``` -**Session Resume:** -- `TaskSession.ACPSessionID` - stored ACP session ID for resume -- `ExecutorRunning` - tracks active executor state (container ID, port, worktree) -- On backend restart: `RecoverInstances()` finds running containers, reconnects streams +1. Orchestrator receives `task.start` 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. @@ -189,47 +174,30 @@ Client (WS) Orchestrator Lifecycle Manager Runtime age ## agentctl Server -### HTTP Endpoints +### API Groups -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/health` | GET | Health check | -| `/api/v1/status` | GET | Agent status | -| `/api/v1/configure` | POST | Configure agent before start | -| `/api/v1/start` | POST | Start agent subprocess | -| `/api/v1/stop` | POST | Stop agent | -| `/api/v1/acp/*` | Various | ACP protocol (initialize, session/*, prompt) | -| `/api/v1/shell/*` | Various | Shell operations | -| `/api/v1/workspace/*` | Various | Git status, file changes | -| `/ws/updates` | WS | Agent event stream | -| `/ws/workspace` | WS | Workspace event stream (git, files, shell) | +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 normalize different agent CLIs: +Protocol adapters in `adapter/transport/` normalize different agent CLIs: - `AgentAdapter` interface defines `Start()`, `Stop()`, `Prompt()`, `Cancel()` -- `ACP` - ACP JSON-RPC over stdio (Claude Code) -- `Codex` - Codex-style JSON-RPC (OpenAI Codex) -- `CopilotAdapter` - GitHub Copilot SDK -- `AmpAdapter` - Sourcegraph Amp CLI +- 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 -## ACP Protocol - -JSON-RPC 2.0 over stdin/stdout between agentctl and agent process. - -**Backend -> Agent (Requests)** -- `initialize` - handshake -- `session/new` - create new session -- `session/load` - resume existing session -- `session/prompt` - send user message -- `session/cancel` - cancel current operation - -**Agent -> Backend (Notifications)** -- `session/update` with types: `message_chunk`, `tool_call`, `tool_update`, `complete`, `error`, `permission_request`, `context_window` +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`. --- @@ -271,11 +239,12 @@ lib/state/ │ └── ui/ # preview, connection, active state ├── hydration/ # SSR merge strategies -hooks/domains/{kanban,session,workspace,settings}/ # Domain-organized hooks +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 ├── user-shell-api, debug-api, secrets-api, sprites-api, vscode-api +├── health-api, utility-api ``` **Key State Paths:** @@ -346,4 +315,4 @@ This file is read by AI coding agents (Claude Code via `CLAUDE.md` symlink, Code --- -**Last Updated**: 2026-02-26 +**Last Updated**: 2026-03-05