Skip to content

Latest commit

 

History

693 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

copilot-tools

Tools, skills, and workflow conventions for GitHub Copilot CLI power users — autonomous loop mode, multi-instance session management, agent-to-agent messaging, and spec-driven workflow conventions.

An independent personal project. Not affiliated with, endorsed by, or supported by GitHub or Microsoft.

What's Inside

Component Description
copilot_operator.py Cross-platform Copilot CLI wrapper with metrics capture, autonomous loop mode, and multi-instance support
operator_runner.py In-pane session supervisor: correct process attribution and metrics after detach
operator_mux.py Session-backend abstraction (tmux / psmux)
work_claims.py One work item, one owner: the claim store behind operator work
operator_liveness.py Whether a claim's owner is provably gone: LIVE / DEAD / STALE
operator_session.py The session lifecycle: the assignment resolved on the way in, the handoff and claim disposal on the way out
operator_work.py The policy over the claim store: operator work, and the reclaim that preserves a departed owner's work first
operator_worktree.py The checkout a claim owns: operator worktree new / finish / recover
operator_ownership.py Whether a branch stayed inside its subproject: operator ownership check
operator_ingest.py Pure-Python log parser for copilot process logs
handoff_tool.py Atomic session handoff for agents
backlog_tool.py Reads and enforces the tracked backlog/; ships the backlog command
operator.sh, handoff.sh, operator-ingest.py Original bash implementation, retained on disk for rollback but no longer installed fresh by setup.sh
skills/code-intelligence Roslyn-backed C# structural analysis
skills/peer-agents Starting peer operator agents and messaging them
skills/worktrees Worktree lifecycle, scratch discipline, safe delegation
skills/backlog The tracked backlog format, the approval gate, and evidence
skills/spec-driven The spec-kit workflow and when a change needs a spec update
skills/field-notes The cross-project journal about working with AI agents
skills/operator-backlog-* Filing, refining and checking in on the tracked backlog
docs/rationale.md Why the rules exist — the incidents behind them. Linked, never loaded
operator_mail.py Message store behind operator send / operator inbox
conversation_log.py One record of everything said to an agent and back: seeds from the session store, the mail store and the capture spool
conversation_viewer.py Loopback web viewer for that record — filter and search by project, day, speaker
operator_trace.py Records who invoked the operator and how each invocation ended, for attributing incidents
install_manifest.py Records what setup deployed and its hash, so upgrades know what's safe to replace
mail_affiliation.py Which project each end of an operator message belongs to — recorded, never enforced
extensions/ Copilot CLI runtime extensions: open-in-vs-code, lint-on-edit, security-shield, test-enforcer, architecture-enforcer, checkout-guard, copy-to-clipboard-tool, conversation-capture
templates/ Configuration templates for copilot-instructions, MCP servers, and per-project setup
docs/ Documentation for operator, skills, versioning, and spec-kit
setup.sh Linux/WSL/macOS setup: migrates any legacy bash install to Python, then delegates to setup_tools.py
setup.ps1 Windows setup: locates or installs Python 3.10+, then delegates to setup_tools.py

Platform Support

Component Windows Linux / WSL macOS
Workflow conventions & templates ✅ ✅ ✅
Spec Kit workflow ✅ ✅ ✅
Runtime extensions ✅ ✅ ✅
operator / handoff (Python) ✅ ✅ ✅
operator.sh / handoff.sh (bash, legacy — rollback target, still tested) ❌ rollback only rollback only
operator restore (Windows Terminal tabs) ✅ (native tabs) ✅ (WSL-hosted tabs only) ❌

The Python implementation is the supported entry point on every platform. setup.sh migrates existing Linux/WSL/macOS installs off the bash scripts automatically (see Quick Start); the bash scripts themselves are left on disk, unmodified by setup, purely so a failed migration can never strand a user without a working operator/handoff command.

Here "legacy" means superseded, not abandoned. A rollback target is only worth having if it still runs, so the bash scripts stay under test: CI's "Shell script syntax" job parses every *.sh with bash -n on every pull request and every push to main, and the suite exercises operator.sh and handoff.sh directly — tests/test_operator_sh_bash32.py, tests/test_handoff_sh.py, tests/test_operator_sh_entrypoint.py, tests/test_operator_sh_help.py and tests/test_shell_bash32_conformance.py all read or run them, the last of those because macOS /bin/bash is permanently 3.2 and macOS is exactly where someone is most likely to need the fallback. They still get bug fixes; they get no new features, and a divergence in behaviour is resolved by changing the bash to match the Python. Don't install them on purpose — see rolling back for the one supported reason to. tests/test_legacy_bash_status.py fails if this paragraph and that coverage ever stop agreeing.

operator restore re-launches tracked Windows Terminal tabs. It works from both native Windows PowerShell and from inside WSL (via wt.exe/wsl.exe interop), but a restore invoked from WSL only sees tabs tracked by that WSL distro and its siblings, not tabs tracked by a native Windows session, and vice versa — the two sides don't share a tab registry.

Session management uses a terminal multiplexer: psmux on Windows, tmux elsewhere. See Operator for details.

Quick Start

PowerShell (Windows)

git clone https://github.com/darinh/copilot-tools.git $HOME\repos\copilot-tools
cd $HOME\repos\copilot-tools
./setup.ps1

bash (Linux/macOS/WSL)

git clone https://github.com/darinh/copilot-tools.git ~/projects/copilot-tools
cd ~/projects/copilot-tools
chmod +x setup.sh
./setup.sh

Setup installs what's missing rather than telling you to go install it. Both scripts locate a Python 3.10+ interpreter — installing one via winget or your distro's package manager if the machine has none — and delegate to setup_tools.py, which is itself cross-platform and idempotent. It will:

  1. Install any missing prerequisites: a terminal multiplexer (psmux via winget, or its GitHub release as a fallback / tmux via apt-get, dnf, pacman, zypper, apk, or brew), git, and the copilot CLI (via npm, pulling in Node.js first if needed)
  2. Install the operator, handoff and operator-ingest console scripts
  3. Link runtime extensions into ~/.copilot/extensions/
  4. Install configuration templates to ~/.copilot/
  5. Install the Anvil plugin, the Spec Kit CLI (specify, via uv), and optionally dotnet-roslyn-mcp

Anything installed to a directory that isn't on PATH yet (npm's global bin, ~/.local/bin, the psmux download) is added to your user PATH, so new shells pick it up.

Only a genuinely unautomatable failure — no package manager at all, or an install that errors — stops setup, and it prints the exact manual command.

Useful flags: --yes (assume yes to overwrite prompts), --status (report what's installed and whether an update is needed, changing nothing), --check-only (report missing prerequisites and change nothing), --no-install-prereqs (old check-and-bail behavior), --skip-optional (skip Anvil, spec-kit, and the MCP servers), --skip-package (skip pip install -e .).

Setup records what it deployed in ~/.operator/install-manifest.json, so a later run can tell "the repository moved on and you never touched your copy" (update silently) from "you customised this" (ask first). After pulling on another machine, python setup_tools.py --status answers whether you need to re-run setup. See Versioning.

Deploying to a second machine

git pull            # or the clone above, on a machine that has none
./setup.ps1         # ./setup.sh on Linux/macOS/WSL — idempotent

Re-run setup after every pull. A pull updates the checkout; it does not touch ~/.copilot/, and it cannot repair the installed package. Two distinct failures follow from skipping it:

  • A new extension or skill loads nowhere. It sits in the repository and nothing announces the gap, because an extension that never loaded cannot report its own absence.
  • A new Python module is not importable at all. An editable install is not a symlink — setuptools writes a finder holding a static table of module name to path, built at install time. git pull updates the source of every module already in that table and cannot add one. The result is a correct checkout, a broken install, and ModuleNotFoundError from a command that worked yesterday.

python setup_tools.py --status reports both: the installed version, every deployed artifact with its state, and whether the installed package still imports. The import check runs in an isolated subprocess from a temporary directory, so it answers a question about the install rather than about the directory the command was run from — from inside the checkout, every module resolves from the current directory and the answer would always be yes.

Do not verify with operator --version: it prints a hardcoded literal that has not moved since July, so it reports the same number whatever you deployed (backlog item 0027).

Two things are per machine and are not deployed by git:

  • Experimental mode. Extensions load only in experimental sessions, and a session without it loads none of them silently. See Experimental default.
  • The conversation store. ~/.operator/conversations.db holds what was said on that machine and is deliberately not in the repository. Run operator conversations seed there; it is idempotent, and re-running it also re-applies corrected classification rules to rows already stored.

You can also invoke python setup_tools.py / python3 setup_tools.py directly if you don't need the migration step below.

sqlite3 is not required — the toolkit uses Python's standard-library sqlite3 module.

Never install this editably from a git worktree

pip install -e copies nothing. It writes the source directory into the interpreter's import path and points the operator and handoff console scripts at it, machine-wide for that interpreter. A git worktree exists in order to be deleted, so an editable install made from one breaks every console script the moment somebody else correctly finishes that branch and runs git worktree remove — and it breaks for them, days later, with no path back to the cause. That has happened twice here.

So the project's PEP 517 backend (worktree_guard_backend.py) refuses to build an editable install when the source directory is a linked worktree, and tells you which checkout to install from instead. Wheels and sdists are unaffected, submodules are allowed, and COPILOT_TOOLS_ALLOW_WORKTREE_INSTALL=1 overrides the refusal if you really mean it. setup_tools.py run from a worktree redirects to the primary checkout on its own and says so.

Repairing a machine that already has one: reinstall from the primary checkout, naming it explicitly rather than relying on the working directory.

python -m pip install -e /path/to/the/primary/checkout --no-deps
What setup.sh does beyond setup_tools.py (Linux/WSL/macOS)

If a previous run of the original bash installer left an operator and/or handoff symlink in ~/.local/bin pointing at this checkout's operator.sh/handoff.sh, setup.sh sets those symlinks aside, runs the Python install, and confirms operator/handoff resolve to the new console scripts before deleting the old symlinks. If anything else occupies those paths instead — a symlink pointing elsewhere, a different checkout, or an unrelated command with the same name — it's moved aside the same way but never auto-deleted, since pip install -e . would otherwise silently overwrite it with no backup of its own; look for a ~/.local/bin/{operator,handoff}.copilot-tools-preexisting-bak file if that happens to you. If the Python install fails, the new commands don't resolve on PATH, or setup is interrupted (Ctrl-C) mid-install, everything is restored automatically and setup.sh exits non-zero — you're never left without a working command.

That migration is all setup.sh still does on its own. Anvil, dotnet-roslyn-mcp, and the Spec Kit CLI used to be installed here, which meant Windows users never got them; they're now provisioned by setup_tools.py on every platform. operator.sh/handoff.sh themselves are still on disk and still maintained (see Platform Support); they're just no longer the thing installed into PATH.

See Spec Kit Workflow for project initialization, commands, upgrades, and parallel-agent coordination.

Usage

# Interactive session with Anvil agent
operator --agent=anvil:anvil --yolo

# Autonomous loop (restarts when agent signals)
operator --loop --name myproject --agent=anvil:anvil

# Restart later — auto-continues from where it left off
operator --loop --name myproject --agent=anvil:anvil

# Reset session numbering
operator --loop --name myproject --fresh --agent=anvil:anvil

# Multiple concurrent loops
operator --loop --name frontend --agent=anvil:anvil
operator --loop --name backend --agent=anvil:anvil
operator list

# Start a loop without attaching, then message it
operator --loop --headless --name payments-api --agent=anvil:anvil
operator send --from backend --to payments-api "POST /charges returns {id, status}"
operator inbox backend

# Usage reports
operator report costs

# What did I ask, and what came back — across every project on this machine
operator conversations seed     # idempotent; run it again whenever you like
operator conversations serve    # opens http://127.0.0.1:8765/

# Per-project feature configuration (which conventions a project opted into)
operator projects

Named loop instances persist the active Copilot CLI session ID, so restarting the same loop after a WSL crash or Windows reboot automatically resumes the prior CLI session.

On Windows, operator also tracks which Windows Terminal tabs are running named instances. After a reboot or crash, operator restore lists tracked tabs so you can pick which to reopen (or operator restore --all for everything), replaying each launch command in a fresh tab so every Copilot session resumes where it left off — no manual re-cd-ing or hunting for session IDs.

See Operator Documentation for full details.

Skills & Plugins

Skill Type Source
code-intelligence User skill (installed to ~/.copilot/skills/) Included in this repo
operator-backlog-newitem User skill (installed to ~/.copilot/skills/) Included in this repo
operator-backlog-refinement User skill (installed to ~/.copilot/skills/) Included in this repo
operator-backlog-scrum User skill (installed to ~/.copilot/skills/) Included in this repo
peer-agents User skill (installed to ~/.copilot/skills/) Included in this repo
worktrees User skill (installed to ~/.copilot/skills/) Included in this repo
backlog User skill (installed to ~/.copilot/skills/) Included in this repo
spec-driven User skill (installed to ~/.copilot/skills/) Included in this repo
field-notes User skill (installed to ~/.copilot/skills/) Included in this repo
Anvil Installable plugin burkeholland/anvil
frontend-design Built-in CLI skill Ships with Copilot CLI
find-skills Built-in CLI skill Ships with Copilot CLI

See Skills Reference for details and setup.

Workflow Conventions

The templates/copilot-instructions.md file establishes conventions for:

  • Project Configuration System — per-project settings stored in ~/.operator/projects/
  • Session Handoff — cross-session continuity via next-session.md files; an unread handoff is archived to superseded/ rather than overwritten, and that archive is never pruned
  • Session History — SQL-based audit trail of work across sessions
  • Spec-Driven Development — specs as the single source of truth (enabled by default)
  • Parallel Agents — SQL-coordinated parallel task execution via todo_claims
  • Operator Agents — parallel peer agents in their own terminals, talking via operator send / operator inbox
  • Branching Strategy — feature branches worked on in worktrees, merged to main, conventional commits
  • Git Worktrees — all work happens in <repoRoot>/.worktrees/; always on, not optional

These live in each project, not in your home directory

Setup no longer copies that file to ~/.copilot/copilot-instructions.md. A file at that path is read by every Copilot session on the machine, in every directory, project or not — and its enrollment section then tells the agent to resolve a project root, read the catalog, and offer to set the directory up. Opening a terminal anywhere started a conversation about the project system.

Instead each registered project gets its own AGENTS.md, holding only the sections its features turned on and naming its project id outright, so nothing in it has a catalog to look up or a directory to enroll:

operator projects retire

That writes every project's AGENTS.md before it touches the global file, archives the global file to ~/.operator/retired/ and verifies the copy by reading it back, and only then removes it. One project that cannot be written stops the removal — the failure mode is the conventions in two places, never in none. A repository that already has an AGENTS.md is asked about and appended to, never overwritten, and regenerating replaces only the block between the copilot-tools managed conventions markers.

If you already keep an AGENTS.md at user scope, it is reported and left alone: it is not this toolkit's file.

Backlog

Open work in this repository lives in backlog/, under version control — one Markdown file per item, with YAML front matter.

backlog list          # one line per item
backlog ready         # what an agent may work right now
backlog new --title "..." --evidence "..."   # file an item, awaiting approval
backlog approve 3     # the owner's act: proposed -> open
backlog close 3       # shipped: records today and the SHA HEAD resolves to
backlog close 3 --reject   # considered and declined; no commit, because none
backlog scrum         # what changed since the last check-in
backlog check         # validate every item; non-zero on failure
backlog html --open   # a self-contained page, in a browser

Three skills drive those commands in conversation: /operator-backlog-newitem files what surfaces mid-task, /operator-backlog-refinement walks the queue with you, and /operator-backlog-scrum reports what changed since you last looked.

It exists because closed work is answerable from git log and open work was answerable from nothing: it lived in next-session.md, which is read-once and deleted at session start, and was carried between sessions as one re-summarised sentence. That carry-forward is lossy by construction and nothing could detect the loss.

An agent files items as proposed, never open: filing is not approving, and backlog ready lists only approved work, so the gate is enforced rather than merely documented. The one exception is narrow and checked — an item carrying blocks: <id> may be worked while the approved item it names is open, so a defect found mid-task has a legal path instead of a stall or a self-approval.

Each item names a spec under specs/, or the literal none. Closing an item means setting status, closed and commit in the same change that does the work, and updating the linked spec there too — a close landing separately from its fix is a window in which the backlog is wrong. In practice the close is the branch's last commit, naming the SHA of the one before it; filling in a SHA and then git commit --amend records an object the amend destroys.

backlog close writes that pair for you and enforces the same gate ready does: it closes only an item an agent was allowed to work, so filing your own item and marking it shipped is not a path. Declining one is --reject, which is deliberately not gated on approval — the ordinary thing to decline is an unapproved proposal — and writes no commit, because nothing shipped. Both verbs are also reachable as operator backlog …, which is a delegation to this same tool rather than a second implementation of it.

tests/test_backlog_conformance.py enforces the format, the spec mapping, and that every closing SHA actually resolves; tests/test_backlog_workflow.py covers filing, approval, closing and the check-in. See backlog/README.md for the field reference.

MCP Servers

An optional MCP server provides structural code intelligence:

Server Language Install
dotnet-roslyn-mcp C# dotnet tool install -g dotnet-roslyn-mcp

Configure in ~/.copilot/mcp-config.json — see templates/mcp-config.json.

Repository Structure

Every entry at the repository root appears below; tests/test_readme_structure.py fails if this tree and git ls-files ever disagree.

copilot-tools/
├── .github/
│   ├── copilot-instructions.md    # Conventions for agents working in this repo
│   ├── skills/speckit-*/          # Copilot skills generated by Spec Kit
│   └── workflows/ci.yml           # 8 jobs: 3 OSes x 2 Pythons, shell syntax, extensions
├── .specify/                      # Spec Kit templates, scripts, and constitution
├── AGENTS.md                      # This repo's own conventions, written by `operator projects`
├── CLAUDE.md                      # The same conventions for Claude Code; imports AGENTS.md
├── specs/                         # Feature specifications, plans, and tasks
├── backlog/                       # Open work, one file per item; see its README
├── .gitattributes                 # Shell scripts check out LF on every platform
├── .gitignore                     # Caches, packaging output, and /.worktrees/
├── FROZEN.md                      # This repo takes safety fixes only; the kernel moved out
├── LICENSE                        # MIT
├── README.md                      # This file
├── pyproject.toml                 # Packaging and console scripts
├── copilot_operator.py            # Operator CLI (all platforms)
├── operator_runner.py             # In-pane session supervisor
├── operator_mux.py                # Session-backend abstraction (tmux / psmux)
├── operator_ingest.py             # Pure-Python log parser
├── operator_mail.py               # Agent-to-agent mail, live and queued delivery
├── conversation_log.py            # What was said to agents and back: store and seeders
├── conversation_viewer.py         # Loopback web viewer for that store
├── operator_trace.py              # Who invoked the operator, and how it ended
├── operator_liveness.py           # Is a claim's owner still there? LIVE / DEAD / STALE
├── operator_session.py            # Session lifecycle: assignment in, handoff out
├── operator_work.py               # `operator work`: request, release, list, heartbeat, reclaim
├── operator_worktree.py           # `operator worktree`: new, finish, recover
├── operator_ownership.py          # `operator ownership check`: did this branch leave its subproject?
├── operator_console.py            # UTF-8 console output
├── project_paths.py               # Project identity: catalog and per-project dirs
├── project_features.py            # The feature vocabulary, and each project's choices
├── project_instructions.py        # Renders each project's AGENTS.md; retires the global file
├── handoff_tool.py                # Session handoff
├── work_claims.py                 # One work item, one owner: the claim store
├── backlog_tool.py                # Backlog parser, validator, and HTML view
├── setup_tools.py                 # Cross-platform environment setup
├── install_manifest.py            # Records what setup deployed; upgrade strategies
├── mail_affiliation.py           # What project each end of a message belongs to
├── copilot_tools_version.py       # The single source of the version number
├── worktree_guard_backend.py      # PEP 517 backend; refuses `pip install -e` of a worktree
├── backfill_unknown_metrics.py    # One-off repair: fabricated zeros to NULL
├── verify_cross_platform.py       # Stdlib-only verification; runs without pytest
├── git_identity.py                # Refuses to certify a history it could not read
├── e2e_restart_loop.py            # End-to-end restart-loop check, real processes
├── setup.sh                       # POSIX bootstrap; finds Python, runs setup_tools
├── setup.ps1                      # Windows bootstrap; same, winget if no Python
├── operator.sh                    # Legacy bash wrapper (Linux/WSL/macOS)
├── operator-ingest.py             # Legacy log parser, used by operator.sh
├── handoff.sh                     # Legacy bash handoff (Linux/WSL/macOS)
├── diagnose-restart-deleter.sh    # Diagnostic: who deleted the restart directory
├── extensions/                    # Copilot CLI runtime extensions; see its README
├── skills/
│   ├── code-intelligence/
│   │   └── SKILL.md               # Roslyn routing
│   ├── peer-agents/
│   │   └── SKILL.md               # Peer operator agents and messaging
│   ├── worktrees/
│   │   └── SKILL.md               # Worktree lifecycle and safe delegation
│   ├── backlog/
│   │   └── SKILL.md               # Backlog format, approval gate, evidence
│   ├── spec-driven/
│   │   └── SKILL.md               # The spec-kit workflow
│   ├── field-notes/
│   │   └── SKILL.md               # The cross-project agent journal
│   └── operator-backlog-*/
│       └── SKILL.md               # Filing, refinement and the check-in
├── templates/
│   ├── copilot-instructions.md    # Source for each project's AGENTS.md; no longer deployed
│   └── mcp-config.json            # MCP server config
├── tests/                         # pytest suite + bash coordination tests
└── docs/
    ├── operator.md                # Operator documentation
    ├── skills.md                  # Skills reference
    ├── versioning.md              # Install manifest and upgrade strategies
    ├── checkout-guard.md          # Stray-artifact guard, and how to tell it is running
    ├── experimental-default.md    # Measurement: the CLI loads no extensions without --experimental
    └── spec-kit.md                # GitHub spec-kit documentation

Versioning

The version lives in one place, copilot_tools_version.py, and pyproject.toml reads it dynamically. Setup records what it deployed — path, version, and SHA-256 — in ~/.operator/install-manifest.json, which is what lets a later run update a file you never touched without prompting while still asking about one you customised.

python setup_tools.py --status   # what's installed, and is it stale?

See Versioning for the artifact states, the hashing rationale, and how to write a version-to-version upgrade function.

License

MIT — see LICENSE.

This is an independent personal project. It is not affiliated with, endorsed by, or supported by GitHub or Microsoft, and it is not an official distribution of the GitHub Copilot CLI. "GitHub", "GitHub Copilot", and "Microsoft" are trademarks of their respective owners and are used here only to describe what this toolkit interoperates with.

About

Tools, skills, and workflow conventions for GitHub Copilot CLI power users - autonomous loop mode, multi-instance session management, agent-to-agent messaging, and spec-driven workflow conventions.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages