copilot-tools
Copilot instructions1 starsChanged 4 months agoMITView on GitHub
Every agent here works in <repo>/.worktrees/<branch>/, and pip install -e records its source directory in the interpreter's import path and points the operator and handoff console scripts at it — machine-wide, for every user of that interpreter. A worktree is created in order to be deleted, so the install is a breakage armed to fire when somebody else correctly finishes that branch and removes it. Twice now that has killed operator and handoff for every agent on the box, and…
- Installs packages
Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.
Of the Copilot instructions files we read, the 2,343 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository23 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- templates/copilot-instructions.mdCopilot instructions
- speckit-analyzeSkill
- speckit-checklistSkill
- speckit-clarifySkill
- speckit-constitutionSkill
- speckit-convergeSkill
- speckit-implementSkill
- speckit-planSkill
- speckit-specifySkill
- speckit-tasksSkill
- speckit-taskstoissuesSkill
- backlogSkill
- code-intelligenceSkill
- field-notesSkill
- operator-backlog-newitemSkill
- operator-backlog-refinementSkill
- operator-backlog-scrumSkill
- peer-agentsSkill
- request-auditSkill
- spec-drivenSkill
- worktreesSkill
The file
We split this copilot-instructions.md into the rules it gives an agent
9 rules. About 0 are common, 3 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 5
Every agent here works in <repo>/.worktrees/<branch>/, and pip install -e records its source directory in the interpreter's import path and …
- Very specific: line 54
Do not narrow that scan to a single file.
- Very specific: line 78
Use ntpath when the string may name either syntax.
- Very specific: line 155
Read .specify/memory/constitution.md and the active feature under specs/ before implementing a non-trivial change.
- Very specific: line 157
Use the speckit-* skills for specification, planning, tasks, implementation, and analysis.
- Very specific: line 159
Keep specs factual and update spec.md, plan.md, and tasks.md with delivered behavior.
- Distinctive: line 167
Use a unique stable agent ID and atomically claim one ready todo before changing files.
- Distinctive: line 169
Never work on a todo claimed by another agent and never steal a claim without coordinator confirmation that its owner has stopped.
- Distinctive: line 173
If preferred work depends on an in-progress todo, leave it pending and select another ready todo instead of waiting.
≈ “Common” is an estimate: at least 1 in 5 of the 3,779 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Repository Agent Instructions
Never pip install -e from a worktree
Every agent here works in <repo>/.worktrees/<branch>/, and pip install -e
records its source directory in the interpreter's import path and points the
operator and handoff console scripts at it — machine-wide, for every user
of that interpreter. A worktree is created in order to be deleted, so the
install is a breakage armed to fire when somebody else correctly finishes
that branch and removes it. Twice now that has killed operator and handoff
for every agent on the box, and both times the person holding the traceback
had no path back to the cause.
Pass the primary checkout explicitly rather than trusting the working directory:
python -m pip install -e C:\Users\darin\repos\copilot-tools --no-depsworktree_guard_backend.py — this project's PEP 517 backend — now refuses to
build an editable install from a linked worktree and names the checkout to use
instead. Submodules, wheels and sdists are unaffected, and
COPILOT_TOOLS_ALLOW_WORKTREE_INSTALL=1 overrides it. Do not weaken the guard
to make a one-off convenient; the override exists for that.
Shell scripts must run on bash 3.2
/bin/bash on macOS is 3.2 — Apple froze it at the last GPLv2 release and is
never going to move it — so on macOS it is the default interpreter,
permanently, not a legacy configuration a user could upgrade out of. Every
*.sh file in this repo runs under set -u, so two bash 4 features are
runtime aborts there rather than warnings:
- Associative arrays.
local -A xisdeclare: -A: invalid option, and underset -ethat ends the run. Use an indexed array with thein_listhelper (operator.sh,handoff.sh) instead. - Expanding an empty array.
"${a[@]}"underset -uis an unbound-variable abort on every bash before 4.4. Write${a[@]+"${a[@]}"}instead — uniformly, including where the array looks provably non-empty. Which arrays can be reached while empty is a fact about today's callers, and callers change.${#a[@]}is safe.
tests/test_shell_bash32_conformance.py enforces this over every first-party
shell script, along with the other bash 4 constructs that would break there
(namerefs, mapfile, coproc, ;;&, [ -v x ], exec {fd}<, ${v@Q},
$'\uXXXX' and more). Every detector has a positive control asserting it
fires and a negative control asserting the portable spelling still passes — a
detector that matches nothing reports the whole tree clean, which reads
exactly like success. Add both when you add a detector.
It is deliberately a static scan: these are the exact tokens bash 3.2 rejects, and CI executes these scripts under a 3.2 interpreter on one leg only, so an execution test cannot object on the other seven.
Do not narrow that scan to a single file. It replaced a tripwire that read
only operator.sh, which is how handoff.sh kept an associative array
through the change that removed operator.sh's — a rule enforced against one
file is not a rule, it is that file's history.
os.path is the running platform's syntax, not "paths"
os.path is an alias for posixpath or ntpath depending on what is
executing it, so it is the wrong tool the moment a string names the other
platform's syntax. On Linux, os.path.basename(r"C:\tools\tmux.exe") returns
the whole string — a backslash is an ordinary filename character there — and
the caller gets c:\tools\tmux.exe where it expected tmux.exe.
That reached main in the test suite's multiplexer guard, which refuses any
spawn of tmux/psmux/pmux so a unit test can never drive a real server.
It extracted the program name with os.path.basename, so the parametrised
full-Windows-path case passed on both Windows legs and, on the four POSIX
legs, the guard missed and spawned. A full green local Windows suite could not
see it, which is the same shape as the setuptools incident above: a green
local suite is evidence about one leg. Before concluding anything from a
local run, check whether main is even green — gh run list --workflow CI
--limit 5 — because you can otherwise spend an evening diagnosing a failure
you inherited.
Use ntpath when the string may name either syntax. ntpath is pure syntax
with no filesystem or platform dependence, and it understands drive prefixes,
UNC paths and both separators, so it is the union of the two rather than a
guess at it. The first fix here was a guess — a hand-rolled split on both
separators — and it read C:tmux.exe, a drive-relative path Windows accepts,
as c:tmux. It closed the POSIX hole by opening a Windows one that
os.path.basename had never had, in the one predicate where under-refusing
costs other agents their live sessions. Only adversarial review caught it.
os.path remains correct where the data provably comes from the running
machine — operator_trace.py reads its own process table, and the choice
there is deliberate, not an oversight to go fix.
Every third-party import must be declared
CI went red on the two Python 3.12 legs on 2026-08-01 and stayed green on the
other four. tests/test_worktree_install_guard.py imports setuptools, and
nothing in pyproject.toml ever said so — it worked for as long as Python
shipped setuptools in a fresh environment, and 3.12 stopped. A full green
local suite could not see it (this machine is 3.11 with setuptools ambiently
installed) and neither could four adversarial review passes across three
models, because an absent line in pyproject.toml is not in the diff.
tests/test_dependency_declaration_conformance.py is what looks now. Every
top-level import in every first-party *.py must resolve to the standard
library, another module in this repo, or a distribution named in
pyproject.toml — [project] dependencies, any
[project.optional-dependencies] extra, or [build-system] requires. If you
add an import, declare it in the same commit.
There is no exemption list, deliberately: try: import x / except ImportError
and imports under TYPE_CHECKING are reported too, because both still bet on
the environment supplying the name. Declare the optional dependency in an
extra instead. Prefer that to pytest.importorskip, which turns "the library
is missing" into a silent skip and retires the guarantee while staying green.
The scan carries its own narrow TOML reader, because tomllib is 3.11+ and
the floor is 3.10. Three things about it are load-bearing. It masks the whole
document before reading any line, because a line-based reader cannot see a
multi-line string, and a description = """...""" containing a line that
reads like dependencies = ["ghost"] then widens the allow-list silently —
the one failure direction this scan cannot afford. IMPORT_NAMES — the table
saying PyYAML is imported as yaml — is checked against
importlib.metadata.packages_distributions(), so a wrong entry fails rather
than silently widening the allow-list. And the parser's controls must contain
a quote or a bracket inside the comment: the first draft's comment cases
used # why, which a parser that never strips comments at all handles
identically, so the whole control set passed with comment handling removed.
A commented-out # "ghost", in a dependency array is the shape that matters.
For the same reason the reference cross-check runs over a corpus of
adversarial documents, not over this repository's own pyproject.toml, which
contains none of these shapes and so proved nothing about any of them.
First-party module names come only from directories that are actually on
sys.path — the repository root plus pythonpath from
[tool.pytest.ini_options]. Taking them from the stem of every *.py in the
tree means one docs/examples/requests.py silently switches the detector off
for requests everywhere, and every control keeps passing because the
controls score against a fixed set. Files deeper in the tree are still
scanned; they just do not get a vote on what counts as ours.
Modules removed from the standard library after 3.10 (distutils, gone in
3.12) are reported on the newer legs only. That is the correct verdict and it
is the setuptools shape exactly — but resolving one costs two edits, not one:
declaring setuptools is not enough, because setuptools does not record
distutils in its metadata, so the mapping goes in IMPORT_NAMES and the
reason goes next to it in IMPORT_NAMES_UNRECORDED. Modules added after
3.10 belong to tests/test_python_floor_conformance.py, not here.
STDLIB is sys.stdlib_module_names and deliberately not "what imports
here". The documented set includes names that do not import on the running
platform — fcntl on Windows, winreg on Linux — so an allow-list built by
importing would be narrower on some legs than others, and import fcntl
would go red on the Windows legs only, with no declaration able to fix it.
Spec-kit workflow
- Read
.specify/memory/constitution.mdand the active feature underspecs/before implementing a non-trivial change. - Use the
speckit-*skills for specification, planning, tasks, implementation, and analysis. - Keep specs factual and update
spec.md,plan.md, andtasks.mdwith delivered behavior.
Parallel todo ownership
- The coordinator must create the shared
todo_claimstable before launching parallel agents:CREATE TABLE IF NOT EXISTS todo_claims (todo_id TEXT PRIMARY KEY, agent_id TEXT NOT NULL UNIQUE, claimed_at TEXT NOT NULL DEFAULT (datetime('now')), heartbeat_at TEXT NOT NULL DEFAULT (datetime('now'))); - Use a unique stable agent ID and atomically claim one ready todo before
changing files. Claiming must be atomic in a short
BEGIN IMMEDIATEtransaction usingINSERT OR IGNORE INTO todo_claims SELECT ...with full condition checks, followed by a guardedUPDATE todos SET status = 'in_progress'that verifies the claim succeeded. - Never work on a todo claimed by another agent and never steal a claim without coordinator confirmation that its owner has stopped.
- A todo is ready only when it is pending, unclaimed, and every dependency is
done. Provide exact ready-work SQL excluding claimed or dependency-blocked todos:SELECT t.* FROM todos t WHERE t.status = 'pending' AND NOT EXISTS (SELECT 1 FROM todo_claims c WHERE c.todo_id = t.id) AND NOT EXISTS (SELECT 1 FROM todo_deps td LEFT JOIN todos dep ON td.depends_on = dep.id WHERE td.todo_id = t.id AND (dep.id IS NULL OR dep.status != 'done')); - If preferred work depends on an in-progress todo, leave it pending and select another ready todo instead of waiting. Do not mark dependency waits as blocked.
- Completion/real blocker/release must update status only when the same agent owns the claim, then delete the claim coherently within a transaction.
- Refresh
heartbeat_atduring long-running work; only the coordinator may recover a stale claim after confirming its owner stopped. - Work in an isolated git worktree. Tasks that modify the same file are
sequential even when they are otherwise marked parallel (
[P]means eligible, not assigned). - In parallel mode, worker agents update SQL status and report completion, but ONLY the coordinator serially reconciles
tasks.mdcheckboxes. Single agents update both SQL andtasks.mddirectly.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

