Skip to content

AbysmalBiscuit/devkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

592 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

devkit

A Rust workspace of six binaries that coordinate local development for a monorepo. Devkit provides flock'd port and file-lock registries (both served from memory by an optional devkitd supervisor daemon), a supervised dev-app runner with baseline A/B comparison, and a single issue command covering the whole issue lifecycle (setup, triage, cleanup, PR status, dashboard, review). All project-specific details live in devkit.toml; the engine itself is project-agnostic.

Binaries

portm: Port Registry

Maintains a shared port registry so concurrent callers never collide on port allocation. State lives in ~/.local/state/devkit/ports.json, guarded by an advisory file lock. Reservation rows are written before any process binds, which prevents the allocation race across concurrent callers.

portm status                                     # table of reserved/live ports
portm alloc <apps…> [--holder <path>] [--role issue|baseline]    # alias: reserve
portm release [apps…] [--holder <path>] [--role …]
portm prune                                      # remove stale reservations

--holder defaults to the current worktree's root (git rev-parse --show-toplevel). release with app names frees only those apps' reservations; it never signals processes (devrun down is stop-and-release).

devrun: Supervised Dev Servers

Launches and supervises dev servers for one or more apps. Apps not explicitly named are auto-detected by diffing git diff <baseline_ref>...HEAD. When any webapp is selected, api is added automatically and FOUNDRY_API_BASE_URL is wired to the local api port. Each app's launch command is run verbatim with {{ port }} substituted; wrap it in doppler run in the config if the app needs Doppler-injected secrets. --role both runs the issue branch and a fresh origin/staging baseline side-by-side on separate ports for direct A/B comparison.

devrun up [apps…] [--role issue|baseline|both] [--env K=V] [--env-file F] [--dry-run]
devrun down [--role …] [--all | --others | --holder <path>] [--app …] [--older-than …] [--batch] [selector]
devrun status [--all]
devrun reap [--all]
devrun logs <app> [-f]
devrun config show [--origin] [--json]
devrun config apps [--json]
devrun config tasks [--json]
devrun task [<name>] [--env K=V] [--env-file F] [--dry-run]
  • config show: prints the effective merged config as TOML. --origin annotates each value with the file it was resolved from (or # (default) for serde defaults); --json emits JSON instead of TOML. --origin --json emits { "config": …, "origins": { "dotted.path": "file" } }.

  • config apps: lists the configured apps from the merged config (columns: name, port, path, provides_url, url_env, launch). --json emits a structured array. A pure config readout with no live readiness — for running state use devrun status.

  • config tasks: lists the configured [tasks] from the merged config (columns: name, kind, app, description) — the same listing as a bare devrun task. --json emits a structured array.

  • down: stops servers and releases their ports. By default stops every server in the current worktree. Reaching another worktree requires an explicit scope flag and a confirmation read from a terminal:

    Command Effect
    devrun down stop all servers in this worktree
    devrun down --role baseline this worktree, baseline only
    devrun down api this worktree, fuzzy-match api across columns
    devrun down --all every server, every worktree (one batch prompt)
    devrun down --others every server in every other worktree
    devrun down --others api api in other worktrees (per-worktree prompts)
    devrun down --holder ../wt/feat-x one specific worktree
    devrun down --all --app api --older-than 1h precise filter, all worktrees

    A positional selector substring-matches across HOLDER/APP/PORT/ROLE/PID and is mutually exclusive with the column filters (--app, --port, --role, --pid, --listening/--not-listening, --older-than). --older-than accepts 90s, 30m, 2h, 1d (bare number = seconds). Any selection that reaches outside the current worktree prints a preview and prompts; with no interactive terminal it is refused. --all/--batch collapse the per-worktree prompts into one.

  • status: lists tracked servers for this worktree (--all for every worktree). Below the tracked table it shows an untracked (outside devrun) section: dev servers detected listening on a configured app's port band, or matching a configured app's launch signature, that the registry doesn't own — i.e. started outside devrun up. Read-only; reaping is a separate command.

  • reap: kills dev servers found running outside devrun (this worktree by default; --all reaches every worktree). It prints the matched process trees, then requires an interactive terminal and a confirmation before sending SIGTERM (escalating to SIGKILL). There is no --yes/--force bypass — with no terminal it refuses and kills nothing, so an agent (no PTY) can never reap. Detection is also available read-only to agents via the ports.strays MCP action; killing is not.

  • task: run a canned [tasks] oneshot or sequence (no name lists them).

issue: Issue Lifecycle

One command covering the whole issue lifecycle. Global -C/--dir and --config flags sit on issue itself, before the subcommand (e.g. issue -C ~/Git/acme/monorepo status).

issue setup <ID> --slug <slug> --apps <a,b> [--dry-run]     # id also accepted as --issue <ID>
issue checkout-pr <PR_LINEAR_ID_URL> [WORKTREE_PATH] [--setup [--apps a,b]]
issue status [ids…]                           # read-only triage table (also the bare `issue`)
issue info [selector] [--json] [--cache-only] # one worktree's PR number + Linear id (defaults to current)
issue end [ids…] [-y] [--force] [--pr-only] [--clean-worktree]
issue prs [-m|--mine] [-r|--reviews] [-R owner/repo] [--no-cache] [--batch-size <N>] [--retries <N>]
issue dashboard [--bucket auto|day|week|month] [--chart bar|line] [--mode absolute|proportional] [--all-roles] [--author <email>] [--no-plots] [--no-cache]
issue review request [<body>] --to <alias|#channel> [--base <branch>] [--pr-title <t>] [--pr-body <b>] [--no-push] [--arg k=v]
issue review finish  [<body>] [--pr <number>] [--to <alias|#channel>] [--arg k=v]
  • setup: mechanical start of a Linear issue. Creates a worktree off the baseline ref, symlinks env files, runs bun install, and prints a JSON summary. It does not reserve ports — devrun up allocates them dynamically when the worktree's servers start.
  • checkout-pr: checks out an existing PR branch into a new worktree (unlike setup, which creates a new branch). The target may be a GitHub PR number (#3340), a bare number (3340 — probed against both GitHub and Linear when a Linear key is configured, prompting on a real collision in a TTY and erroring if ambiguous without one; treated as a GitHub PR when no Linear key is present), a Linear id (ENG-3340, whose attached PR is used — an issue with no attached PR is an error), or a GitHub/Linear URL. The worktree directory is named by the templates.checkout_worktree_dir template (variables: pr_number, pr_title, linear_id, linear_title; titles are slugified; linear_* are empty on the PR-only path); the default renders e.g. 3340-fix-login, or 3340-fix-login_[ENG-42] when reached via Linear. Pass [WORKTREE_PATH] to override the placement. The PR's own branch name is kept; the template governs only the directory. Add --setup [--apps a,b] to also run the per-app prep pipeline, exactly as issue setup does. The worktree gets a .devkit/issue.toml record so issue status/issue end recognise it.
  • status (the default when you run bare issue): triage table of every issue worktree. A worktree is FINISHED only when its PR is MERGED, its Linear issue is Done, and the working tree is clean.
  • info: shows one worktree's PR number and Linear id. The optional selector is an issue id, branch, worktree basename, or path; omit it for the current worktree. --json emits a single machine-readable object (the IssueWorktree struct, with pr_number/issue_id for scripts). --cache-only skips the network — the PR number comes from the per-worktree cache at <worktree>/.devkit/pr.json and Linear state renders as . A live run writes the PR through to that cache, which git worktree remove deletes with the worktree.
  • end: removes FINISHED worktrees. --pr-only ignores the Linear and issue-id gates (finished = PR merged + clean, even without a Linear-style branch name); --clean-worktree targets explicit selections; --force overrides the dirty-tree guard; -y skips confirmation.
  • prs: GitHub PR triage of your open PRs and PRs awaiting your review, with a per-repo diff cache that renders old → new for anything changed since the last run. The three searches (authored, review-requested, reviewed-by) run concurrently, each paged at --batch-size (default 25) and followed to exhaustion, so the table is complete however many PRs are open. Lower the batch size if GitHub answers a page with HTTP 504 — the per-PR check and review selections are what make a page expensive. --retries <N> (default 0) re-attempts a failed page with backoff.
  • dashboard: the triage + PR tables, plus terminal timelines of your Linear issues by status, PRs opened/merged, and commits over time (--chart bar or line). The timeline fetches (Linear + GitHub) are cached under ~/.cache/devkit/dashboard for a few minutes so reruns are fast; the live triage/PR panel is never cached. --no-plots shows only the tables; --no-cache forces a fresh fetch.
  • review: two subcommands — review request (push, open/reuse PR, add GitHub reviewers, Slack them) and review finish (Slack the PR author when you are done reviewing). See below.

On a TTY, issue and issue info draw the triage table immediately and fill in each cell with an animated braille spinner as git, GitHub, and Linear data land. issue prs shows the previous run's tables dimmed with a fetch spinner below noting they are as of the last run (stale-while-revalidate), then swaps the fresh tables in place — the two renders are line-for-line parallel, so the screen does not shift. The step-driven commands (checkout-pr, setup, end, review) keep every completed step on screen as a numbered log line with its elapsed time. All of this live rendering goes to stderr and is TTY-gated — stdout, piped output, and redirected output are unaffected.

issue review request

Push the branch, open or reuse the PR, request review on GitHub, and Slack the reviewers.

issue review request "ready for a look" --to igor
issue review request --to igor --to '#eng' --arg team=infra   # body optional; channel + people
issue review request                                          # re-ping the PR's existing reviewers
  • --to <alias|#channel> (repeatable). People are added as GitHub reviewers (those with a github handle) and Slacked; #channels are Slack-only. Omit --to to re-request and Slack the PR's current human reviewers.
  • --base, --pr-title, --pr-body, --no-push as before.
  • --arg key=value (repeatable) overrides a variable declared in [templates.variables].

issue review finish

Announce over Slack that you finished reviewing. Posts nothing to GitHub.

issue review finish "LGTM, merging after CI"          # inside the PR's worktree → notifies the author
issue review finish --pr 1234 --to lev                # from anywhere, explicit PR + recipient
  • Resolves the PR from the current branch, or --pr <number> when run outside a worktree.
  • Defaults to notifying the PR author; --to overrides (repeatable, people or #channels).
  • --arg key=value as above.

Templates: review_request and review_finish under [templates]. Per-recipient render fields: name (alias or channel), slack_id (user id, empty for channels), plus pr_url, pr_title, input (and author for finish).

Timing (--timing)

issue and devrun accept a global --timing flag that prints a per-operation breakdown of subprocess and network IO to stderr on exit:

  • --timing (or --timing=summary) — a table of ops (git fetch, github REST, linear graphql, …) with count / total / max / p50, plus a headline showing wall time, IO-busy time, serial sum, and the concurrency factor the parallel fan-outs achieve.
  • --timing=trace — additionally lists every op with its start offset, thread, and full command line.
  • --timing-log <FILE> — streams one JSON record per op (op, detail, start_ms, dur_ms, thread) for comparing runs.

DEVKIT_TIMING=summary|trace enables the summary/trace form without the flag. stdout (tables, --json) is never affected. Example:

issue status --timing

lockm: File Locks

Advisory locks on paths so parallel sessions sharing one checkout (where per-session worktrees are too expensive) don't edit the same files at once. A flock-guarded registry of claims keyed by path, the file-level twin of portm. Locks are exclusive and overlap by path component, so locking a directory conflicts with locking a file inside it.

lockm acquire <paths…> [--as <id>] [--note <msg>] [--ttl <secs>] [--json]
lockm release <paths…> [--as <id>]        # or: release --all
lockm check   <paths…> [--json]           # read-only: would acquire succeed?
lockm status  [--all] [--json]            # alias: list
lockm prune

Sessions identify themselves by (in priority order) --as <id>, $DEVKIT_SESSION, $TMUX_PANE (zero-config and unique per tmux pane), the controlling tty, or the parent pid. Conflicts fail fast: acquire/check exit 1 and report who holds the path. Locks expire after their TTL (default 30 min, --ttl 0 disables) or when a recorded anchor pid dies; release frees them explicitly. For non-interactive agent sessions, pass a stable --as/$DEVKIT_SESSION so acquire and release agree.

devkit: Setup & Diagnostics

Configures and diagnoses the toolkit itself. auth validates a Linear or Slack credential against the live API and stores it in ~/.config/devkit/secrets.toml (0600); doctor reports where each credential resolves from and whether it is valid. Tokens always resolve env-first, so a shell export or Doppler-injected var still wins.

devkit auth <linear|slack> [--token <value>]   # validate + store; prompts (no echo) by default
devkit doctor [--json]                          # check configured credentials
devkit brief                                    # compact project brief (apps, tasks, live servers)
devkit completions <shell>
  • auth: prompts for the token without echo (or reads --token/piped stdin), validates it, and saves it. For Linear it also stores the workspace slug derived from the API, so issue links work without setting LINEAR_WORKSPACE.
  • doctor: one row per credential — source (env/file/unset) and live validity. Exits non-zero only when a credential that is set fails validation. Also warns when the installed binaries are older than the newest devkit plugin checkout in ~/.claude/plugins/cache (skewed binaries make agents follow docs for features the binaries lack), when servers run outside devrun, and when the docs cache holds unreferenced checkouts.
  • brief: prints a compact orientation for the current checkout — configured apps, the [tasks] table, and this worktree's live servers — and prints nothing outside a devkit-managed project (no project devkit.toml found and no configured app directory present under the worktree root). The plugin's SessionStart hook runs it so coding-agent sessions start already knowing the project's apps and tasks.

docm: Library Docs

Version-correct local library checkouts backing the devkit:docs skill. Register a library once; every lookup resolves the version the current project's lockfile pins and materializes a detached worktree for it under ~/.local/share/devkit/docs/.

docm add tokio                    # registry lookup (crates.io/npm/PyPI)
docm add https://github.com/godotengine/godot --ref 4.3-stable
docm add react --project          # write to this repo's devkit.toml [docs]
docm info tokio                   # path + version + layout map + notes
docm path tokio                   # just the checkout path
docm sync                         # fetch clones, move default worktrees
docm prune                        # drop checkouts no live project references

Global manifest: ~/.config/devkit/docs.toml. Per-project overlay: [[docs.libs]] entries in devkit.toml (same fields; partial entries override the global entry field-by-field). Resolution: manual ref pin → lockfile version (Cargo.lock, pnpm-lock.yaml, package-lock.json, bun.lock, uv.lock) → git tag → default branch fallback.

devkit-mcp (MCP server)

devkit-mcp exposes devkit's port and file-lock coordination to MCP-capable coding agents over stdio. It presents two tools:

  • devkit_describe: list the available actions, or fetch one action's argument schema ({"action": "locks.acquire"}).
  • devkit_call: invoke an action, e.g. {"action": "locks.acquire", "args": {"root": "/path/to/repo", "paths": ["src/a.rs"]}}.

v1 actions: ports.{status,alloc,release,prune} and locks.{acquire,check,release,status,prune}. Pass root (the project path) on every lock call and on ports.alloc/ports.release. For locks, holder is a session identity minted from $DEVKIT_SESSION (or a per-process id). For ports, holder defaults to root (the worktree path the registry uses to track liveness). Either can be overridden per call.

Phase-2 devrun actions: devrun.status (tracked servers for a worktree, or all), devrun.up (start servers, non-blocking: returns each server starting; poll devrun.status for readiness), devrun.down (stop + release a worktree's servers), and devrun.logs (tail a tracked app's log). All take root (the worktree); up is issue-role only and starts servers under a running devkitd when present, else detached.

The MCP server also exposes two read-only issue actions: issue.status lists the issue worktrees for a directory (root, default .; optional ids filter) with each one's PR state, Linear state, and a finished/not-finished verdict; issue.prs triages your GitHub PRs (mine, reviews, neither set means both; optional repo). Both return structured JSON with the verdicts and next-action labels pre-computed. They never mutate; issue review/issue end stay CLI-only.

See Installing for coding agents below for how to register it — either bundled in the devkit plugin or as a standalone MCP server, per host.

Installing for coding agents

devkit ships two things for agents:

  • a plugin — the using-devkit skill, session-start hooks, and the devkit-mcp server, bundled together; and
  • the devkit-mcp server on its own, for hosts without a plugin system.

Either way the binaries must be on your PATH — the plugin's MCP entry and every config below invoke devkit-mcp by name (see Install for feature flags).

The plugin bootstraps them for you. Claude Code, Codex, and Cursor have no install-time hook, so a session-start hook checks for devkit, lockm, and devkit-mcp and, when they are missing, runs the dist installer for the GitHub release matching the plugin's own version — so the binaries stay in lockstep with the hooks and MCP server that drive them. It re-runs on plugin update, when the version moves.

Two cases where it stays out of the way:

  • Binaries already on PATH that the hook did not install (cargo install, a distro package, a source build) are never overwritten — the hook records them as externally managed and leaves upgrades to you.
  • DEVKIT_NO_BOOTSTRAP=1 disables it outright.

A failed install (offline, say) never blocks the session; it warns and does not retry until you resolve it or delete ${XDG_STATE_HOME:-~/.local/state}/devkit/bootstrap-failed.

On Windows the hook runs under Git Bash when it is present and under PowerShell otherwise, so it does not depend on a bash being installed. Both paths resolve the same state directory, so gaining Git Bash later does not reinstall.

To install the binaries yourself instead, see Install:

cargo install --path .

Claude Code

Installing the plugin registers the skill, the hooks, and the MCP server in one step — the plugin manifest points at .mcp.json, so enabling the plugin starts the server automatically.

From the terminal:

claude plugin marketplace add AbysmalBiscuit/devkit   # or a local path to this repo
claude plugin install devkit@devkit

Or in a session, same arguments (/plugin alone opens the interactive browser):

/plugin marketplace add AbysmalBiscuit/devkit
/plugin install devkit@devkit

Restart Claude Code so the hooks load, then run /mcp to confirm the devkit server is active and devkit_describe/devkit_call are listed.

MCP server only (no skill/hooks): the repo ships .mcp.json at the root, so opening this repo in Claude Code registers the devkit server project-scoped.

Codex

From the terminal:

codex plugin marketplace add AbysmalBiscuit/devkit    # or a local path / git URL
codex plugin add devkit@devkit

Codex registers the using-devkit skill natively from the plugin manifest, so it is announced in every fresh session, and starts the bundled devkit MCP server. Confirm with codex plugin list and codex mcp list.

MCP server only (no skill/hooks): the repo ships .codex/config.toml with [mcp_servers.devkit], registering it project-scoped. Project MCP servers load only in trusted projects, so trust this repo when Codex prompts.

Cursor

Cursor has no git-repo plugin install from the CLI. Install the plugin from the Customize panel in the sidebar, or, for a team, from Dashboard → Plugins → Team Marketplaces → Add Marketplace → Import from Repo (AbysmalBiscuit/devkit). For local development, symlink the checkout:

ln -s "$(pwd)" ~/.cursor/plugins/local/devkit

MCP server only (no skill/hooks): the repo ships .cursor/mcp.json (same mcpServers shape as Claude Code's), registering it project-scoped.

Other agents (Zed, generic MCP clients)

No plugin manifest exists for these. Register devkit-mcp as a stdio MCP server in the host's own config — the command is just devkit-mcp (on PATH after cargo install) — and point the agent at AGENTS.md for context. Zed reads AGENTS.md directly.

After wiring up any host, confirm devkit_describe and devkit_call appear.

Configuration

Config is layered. Every devkit.toml from the filesystem root down to the cwd is merged, with ~/.config/devkit/config.toml as the lowest-precedence base layer beneath them all. Deeper files override shallower ones per value: tables merge key-by-key, while scalars and arrays replace wholesale. devrun config show prints the merged result; --origin traces each value to the file it came from.

Two escapes bypass the walk:

  • [config] root = true in a devkit.toml stops the upward walk at that file and drops every shallower layer, including the home config — full isolation.
  • --config <path> or $DEVKIT_CONFIG selects a single file verbatim, with no layering or home base.

App path is normally inferred from the monorepo's doppler.yaml; individual [apps.<name>] sections may override it with an explicit path. launch is run verbatim, so a Doppler wrapper lives in each app's launch; devkit refuses to start a Doppler launch whose config resolves to prd, so it can't run against production secrets.

App conventions are config-driven, not hardcoded:

  • provides_url = true marks the app that serves the URL other apps consume (the API). Consumer apps name that variable in their own url_env; devrun wires it to the provider's local port and auto-includes the provider when a consumer is run.
  • prep_files declares files written into an app's directory during issue setup (before its setup commands). Each is { path, content, overwrite }; content is rendered as a minijinja template with the issue context (prefix, issue, slug, apps, app, branch, worktree), and existing files are kept unless overwrite = true.
  • defaults.apps_dir (default apps) is the repo-relative directory apps live under; it drives path inference and diff-based app detection.

Setting up your config

The config is personal (worktree paths, app catalog, teammate handles, local secrets) and is not distributed; keep it out of version control. See docs/configuration.md for the full config reference and a sanitized example. Copy that example to your config location and edit it:

mkdir -p ~/.config/devkit
$EDITOR ~/.config/devkit/config.toml   # paste & adapt the example from docs/configuration.md

Templates

issue setup and issue review render five strings from optional minijinja templates under [templates]. Each unset key falls back to a default that matches the historical hardcoded output.

[templates]
branch          = "{{ prefix }}{{ issue }}-{{ slug }}"
worktree_dir    = "{{ slug }}"
pr_title        = "{{ issue }}: {{ input }}"
pr_body         = "Closes {{ issue }}.\n\n{{ input }}"
review_request  = "{{ input }} {{ pr_url }}"
review_finish   = "{{ input }} {{ pr_url }}"

[templates.variables]            # constants; a context field of the same name wins
team = "platform"
Key Default Context
branch, worktree_dir {{ prefix }}{{ slug }}, {{ slug }} prefix, issue, slug, apps
checkout_worktree_dir {{ pr_number }}-{{ pr_title }} (or {{ pr_number }}-{{ pr_title }}_[{{ linear_id }}] via Linear) pr_number, pr_title, linear_id, linear_title
pr_title {{ input }} review base + input = --pr-title
pr_body {{ input }} review base + input = --pr-body, pr_title
review_request {{ input }} {{ pr_url }} review base + input = body arg, pr_title, pr_url, name, slack_id
review_finish {{ input }} {{ pr_url }} pr_url, pr_title, author, input, name, slack_id

Review base context for review_request: branch, issue/slug/apps from the .devkit/issue.toml record issue setup writes in the worktree, plus pr_url, pr_title, and per-recipient name/slack_id. issue setup also adds .devkit/ to your global gitignore (--no-gitignore skips it). An undefined variable is an error (strict mode), so typos surface immediately.

Install

Prebuilt binaries (no Rust toolchain)

The quickest path — the dist-generated installer downloads the matching binaries from the latest GitHub release, verifies checksums, and puts them on your PATH:

# Linux / macOS / WSL
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/AbysmalBiscuit/devkit/releases/latest/download/devkit-installer.sh | sh
# Windows (PowerShell)
irm https://github.com/AbysmalBiscuit/devkit/releases/latest/download/devkit-installer.ps1 | iex

Pin a specific release by swapping latest/download for download/v0.8.0. Prebuilt targets are Linux x86_64 (gnu + musl) and arm64, macOS x86_64 and arm64, and Windows x86_64 and arm64. Upgrade in place later with devkit-update.

The installer places only the binaries. To use devkit inside a coding agent, register the plugin afterward — see Installing for coding agents.

From source

Install all binaries (portm, devrun, issue, lockm, devkit, devkit-mcp, devkitd) into ~/.cargo/bin with one command — from a clone:

cargo install --path .

or straight from GitHub without cloning:

cargo install --git https://github.com/AbysmalBiscuit/devkit --force

This builds with default features, which include the devkitd supervisor daemon. devkitd serves both the port registry (ports.sock) and the lock registry (locks.sock) from memory, writing through to the files, and is used by devrun up --supervise. To skip the daemon, build a lean set with --no-default-features (omits devkitd and devrun's --supervise support).

Or just build into target/release without installing:

cargo build --release

Shell completions

The CLIs generate their own completion scripts via a completions <shell> subcommand (bash, zsh, fish, elvish, powershell). For example:

issue completions zsh   > ~/.zfunc/_issue
devrun completions zsh  > ~/.zfunc/_devrun
portm completions zsh   > ~/.zfunc/_portm
lockm completions zsh   > ~/.zfunc/_lockm
# bash:
issue completions bash > ~/.local/share/bash-completion/completions/issue

State & Cache Locations

Data Path
Port registry ~/.local/state/devkit/ports.json
Server logs ~/.local/state/devkit/logs/
File-lock registry ~/.local/state/devkit/locks.json
PR diff cache (issue prs) $XDG_CACHE_HOME/devkit/pr-status/ (or ~/.cache/devkit/pr-status/)
Docs library manifest ~/.config/devkit/docs.toml
Docs library checkouts $XDG_DATA_HOME/devkit/docs/ (or ~/.local/share/devkit/docs/)

The state home honors $XDG_STATE_HOME (default ~/.local/state). A legacy ~/.claude/state/devkit home is migrated automatically on first run.

Requirements

Required:

  • git
  • gh (GitHub CLI, authenticated)

Optional:

  • doppler: only if an app's launch wraps its command in doppler run (see docs/configuration.md)
  • $LINEAR_API_KEY: enables the Linear issue-Done gate in issue status/issue end and the issue timeline in issue dashboard
  • $LINEAR_WORKSPACE: enables clickable Linear issue links in issue status
  • $SLACK_TOKEN: lets issue review post the reviewer message directly (otherwise it emits a SlackIntent JSON object)

Each of these resolves env-first, then from ~/.config/devkit/secrets.toml. Run devkit auth <linear|slack> to store them, or devkit doctor to check them.

Troubleshooting

Recoverable failures print the full error context chain. On a panic, the binary prints a bug report with the location and a backtrace. For a backtrace on either, set RUST_BACKTRACE=1.

About

A rust devkit for running multiple parallel agents

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages