♻️ Keep agent content on standard paths, drop client shims (#11719)

* ♻️ Keep agent content on standard paths, drop client shims

Agent guidance stays where the ecosystem reads it: AGENTS.md at the
root and the skills in .agents/skills. Codex scans .agents/skills and
follows symlinks, opencode lists it among its discovery locations, and
Cursor, Zed, Warp, Cline and Amp use the same project path.

Claude Code reads neither, so it needed CLAUDE.md and .claude/skills.
Committing those two paths is not a neutral default. Both are
gitignored, git treats ignored files as expendable, and a checkout
that needs the path deletes whatever a contributor keeps there without
a warning. Neither sparse-checkout nor skip-worktree offers a way out,
because both make the next pull abort. The two links are now created
by the contributor, once per clone, and documented in
.agents/README.md.

AGENTS.local.md and .agents/local/ give every client one personal
layer that composes on top of the shared one, instead of one file per
client inside the repository.

sync-workspace seeds the two links for ws1 and above, the way it
already seeds the gitignored config.js, so the devenv workflow does
not change.

AI-assisted-by: claude-opus-5
Signed-off-by: Álvaro Tejero Cantero <alvorithm@teje.ro>

* ♻️ Lean on Claude Code reading AGENTS.md, drop the pointer

Claude Code 2.1.277 reads AGENTS.md through the built-in agents-md
plugin, whose default mode loads it in a project that has no
instruction file of its own. Deleting the committed CLAUDE.md is what
turns that on here, so the pointer a Claude user had to create is no
longer part of the setup, and only the .claude/skills link remains:
the plugin covers instruction files, and skills still load from that
path alone.

The instruction that replaces the pointer is a removal. A CLAUDE.md,
.claude/CLAUDE.md or CLAUDE.local.md anywhere from the root down to
the working directory hands the project back to CLAUDE.md and hides
this repository's AGENTS.md, while .claude/rules/*.md and the
person's own ~/.claude/CLAUDE.md do not count and stay usable for
personal steering. CLAUDE.local.md joins the ignore list, and a hard
rule in AGENTS.md forbids all three.

The docs name the version, say the fallback has not reached Bedrock,
Vertex or Foundry, and say the stable auto-update channel runs about
a week behind the default one, so the symlink is documented as the
stopgap for those cases and as something to drop afterwards.

sync-workspace seeds the skills link alone for the same reason.

AI-assisted-by: claude-opus-5
Signed-off-by: Álvaro Tejero Cantero <alvorithm@teje.ro>

* 📎 Remove skills directory mention on AGENTS.md

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

---------

Signed-off-by: Álvaro Tejero Cantero <alvorithm@teje.ro>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
Álvaro Tejero-Cantero 2026-09-22 08:43:25 +02:00 committed by GitHub
parent 79c98b7c2e
commit d8fddf9942
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 72 additions and 7 deletions

View File

@ -34,6 +34,39 @@ the "agentic devenv" (`--agentic`) from the technical guide, which
runs the client outside devenv and wires it in over MCP — here the
client lives inside the sandboxed devenv docker.
The content lives at the paths the ecosystem agreed on: `AGENTS.md` at the
repository root and the skills in this folder, `.agents/skills/`. Codex,
opencode, Cursor, Zed, Amp, omp and pi read both without any setup.
Claude Code reads `AGENTS.md` from 2.1.277, through the built-in
`agents-md` plugin, but only in a project that has no instruction file of
its own. A `CLAUDE.md`, `.claude/CLAUDE.md` or `CLAUDE.local.md` anywhere
from the repository root down to your working directory hands the whole
project back to `CLAUDE.md`, and this file's guidance stops arriving. Keep
none of them here. Personal steering goes in `AGENTS.local.md`, or in
`.claude/rules/*.md` and `~/.claude/CLAUDE.md`, which the plugin does not
count and which therefore leave the project guidance in place.
Skills are untouched by that plugin and still load from `.claude/skills`
alone, which is not committed, so link it once per clone:
```bash
mkdir -p .claude && ln -s ../.agents/skills .claude/skills
# or, with Node:
npx skills add ./.agents/skills --agent claude-code
```
Below 2.1.277, and on Bedrock, Vertex and Foundry where the fallback has
not arrived, add `ln -s AGENTS.md CLAUDE.md` and drop it once your client
has the feature. The auto-update channel decides when that is: `latest`,
the default, has it; `stable` runs about a week behind; Homebrew and the
Linux packages update by hand. Personal skills go in
`.agents/local/skills/<name>/`.
Every one of those paths is gitignored, so your own files keep working and
no checkout overwrites them. Inside the devenv, `ws0` sees the links from
the live checkout, and `ws1` and above are seeded on their first sync.
Unlike the agentic devenv, running the client inside the devenv
docker gives it full access to the live environment: every
dependency already resolved by the image, so the agent can write

View File

@ -1 +0,0 @@
../.agents/skills

3
.gitignore vendored
View File

@ -98,10 +98,13 @@ opencode.json
*.iml
/.claude
/CLAUDE.md
/CLAUDE.local.md
/.playwright-mcp
/.devenv/mcp/
/opencode.json
/.agents/plans
/.agents/local/
/AGENTS.local.md
/.opencode/reports
/.opencode/prompts
/.ci-logs

View File

@ -14,9 +14,9 @@
- **Never pipe test output directly to filters** (`| head`, `| tail`, `| grep`, etc.).
Always redirect to a file first: `command > /tmp/output.txt 2>&1`, then read/grep the file.
This prevents hiding test failures. See `mem:testing` for details.
- **`.claude/skills` is a symlink to `.agents/skills`.**
Edit skills only in their canonical location (`.agents/skills`); never edit
through `.claude/skills`.
- **Read `AGENTS.local.md` after this file whenever it exists.** It carries
the developer's steering for this project and overrides this file on prose style and
workflow, but not on project policy, where instructions here prevail.
- **Commit message body lines MUST wrap at ≤76 chars** (subject ≤70 chars) and
the commit MUST pass `./scripts/check-commit` with exit code 0 before you
consider it done. This is mechanically checked — do not eyeball it.

View File

@ -1,3 +0,0 @@
Read and follow the instructions in `AGENTS.md`.
Treat `AGENTS.md` as the canonical project instruction file.

View File

@ -38,6 +38,22 @@ Center](https://help.penpot.app/).
- **Issue tracker**: We use [GitHub Issues](https://github.com/penpot/penpot/issues)
for public bugs and [Taiga](https://tree.taiga.io/project/penpot/) for
internal project management. Changelog entries reference both.
- **AI coding agents**: guidance lives in `AGENTS.md` and the skills in
`.agents/skills/`, which Codex, opencode, Cursor, Zed, Amp, omp and pi read
without setup. Claude Code reads `AGENTS.md` from 2.1.277, but only in a
project that has no instruction file of its own, so keep no `CLAUDE.md`,
`.claude/CLAUDE.md` or `CLAUDE.local.md` in your checkout: any one of them
hides this repository's guidance from your session. Skills still load from
`.claude/skills` alone, so link it once per clone with
`mkdir -p .claude && ln -s ../.agents/skills .claude/skills`, or with
`npx skills add ./.agents/skills --agent claude-code`. Below 2.1.277, and
on Bedrock, Vertex and Foundry where the fallback has not arrived, add
`ln -s AGENTS.md CLAUDE.md` and remove it once your client has the
feature. Personal instructions belong in `AGENTS.local.md`, personal
skills in `.agents/local/skills/`, and personal Claude steering in
`.claude/rules/*.md`, which Claude loads beside the project instructions
without switching the fallback off. Every one of these paths is
gitignored.
## Reporting Bugs

View File

@ -90,6 +90,12 @@ the frontend's MCP flag) is copied into each workspace on its initial sync
only. After that the developer maintains it in each workspace; subsequent
`--sync` runs leave the workspace copy alone.
The Claude Code skills link, `.claude/skills`, is seeded the same way: it is
gitignored, so the sync does not carry it, and the first sync creates it as a
link to `.agents/skills`. A workspace that already has that path keeps what it
has. No `CLAUDE.md` is created, because Claude Code reads `AGENTS.md` itself
in a project that has none.
Stopping is equally flexible — each workspace is independent. Shared infra
stops only when no instances remain running:

View File

@ -511,6 +511,17 @@ function sync-workspace {
install -D "$PWD/$cfg" "$workspace/$cfg"
fi
# Initial seed of the Claude Code skills link. It is gitignored, so git
# ls-files does not list it, yet Claude Code reads skills from
# .claude/skills alone. Seeded only when absent: afterwards the
# workspace copy belongs to the user, who may keep their own. No
# CLAUDE.md is seeded: Claude Code reads AGENTS.md itself in a project
# that has none, and a CLAUDE.md here would switch that off.
if [[ ! -e "$workspace/.claude/skills" && ! -L "$workspace/.claude/skills" ]]; then
mkdir -p "$workspace/.claude"
ln -s ../.agents/skills "$workspace/.claude/skills"
fi
(
cd "$workspace"
git switch -C "${instance}/${CURRENT_BRANCH}" >/dev/null