Portable, tool-agnostic AI coding harness generator. One source of truth,
AGENTS.md as the entrypoint, no vendor lock-in.
- Quick Start
- Why seh
- Layers
- The two shapes of
AGENTS.md - Commands
- Harness Packages
- Skills
- Memory
- Agent skill directories
- Installation
- Try it (sandboxed demo)
- Development
curl -fsSL https://raw.githubusercontent.com/manuuuel/seh/main/scripts/install.sh | sh
# Once per machine: unified global ruleset + agent symlinks
seh init --global --agents claude,codex --yes
# Per project: detect stack, scaffold AGENTS.md + .seh/
cd your-project
seh init --tech typescript --yes
# Regenerate generated files after editing .seh/ sources
seh syncThis gives you a ~/.seh/AGENTS.md global ruleset symlinked into your
agents' config paths, plus a project AGENTS.md (and CLAUDE.md,
GEMINI.md, …) that every supported agent reads automatically.
seh produces the context files that AI coding agents (Claude Code, Codex,
Gemini, Pi, OpenCode, Copilot, …) read: a single global ruleset on your
machine plus a per-project index of focused, technology-specific
guideline modules. Skills from a harness package are distributed to every
agent that supports them. Edit one source of truth, run seh sync, and
every tool-specific file regenerates in lockstep — no more copy-pasting the
same rules into CLAUDE.md, GEMINI.md, and .github/copilot-instructions.md
separately.
| Layer | Location | What it is |
|---|---|---|
| L0 — Core | bundled in the CLI | The authored source content (global sections + per-technology catalog). Fallback when no package is active. |
| L1 — Global | ~/.seh/ |
A single unified AGENTS.md with your cross-cutting rules. Authored once per machine; optional agent symlinks. Not copied into repos. |
| L2 — Project | <repo>/AGENTS.md + .seh/ |
A thin index linking project + per-technology modules. Committed to the repo. |
| Package | <your-harness>/ |
A versioned git repo of global rules, stack modules, templates, and skills. Takes precedence over L0/L1 when active. |
Resolution order for any file: package → ~/.seh/ → seh bundled core.
Global rules apply everywhere; project layers extend — never contradict them.
Generated files must NOT be hand-edited. Edit the .seh/ sources and run
seh sync to regenerate.
-
Global (
~/.seh/AGENTS.md) is one self-contained file — every guardrail inlined in a single document, led by a forced Craftsmanship principle (keep it small and sharp, write elegant code, seek the most minimal better-working design, introduce no slop). Tools that auto-load a global instructions file get the whole ruleset directly. -
Project (
<repo>/.seh/AGENTS.md) is the canonical file — a short directive preamble plus a progressive index (linked table of contents) pointing at focused modules under.seh/, loaded on demand:.seh/project.md— mission, constraints, out-of-scope (read-first).seh/domain/*.md— architecture, glossary.seh/stack/<tech>.md— per-technology best practices
Tool-specific files (
AGENTS.md,CLAUDE.md,GEMINI.md,.github/copilot-instructions.md, etc.) are generated symlinks to.seh/AGENTS.md, gitignored, and regenerated byseh sync.
seh init --global # interactive: choose which agents to symlink
seh init --global --agents claude,codex --yes # non-interactiveCreates:
~/.seh/AGENTS.md— the unified global ruleset (Craftsmanship first, then security, quality gates, testing, commits, branching, dependencies, error handling, observability, data & privacy, documentation, refactoring, workflow, session startup, reporting, boundaries, code principles).~/.seh/config.json— which agents are symlinked.
Optionally wire agents to auto-load it (see seh link).
cd your-project
seh init # detects technologies, interactive multi-select
seh init --tech typescript,python --yes # non-interactive (≥1 required)Creates:
AGENTS.md— the project index (links to the modules below).seh/project.md,.seh/domain/architecture.md,.seh/domain/glossary.md.seh/stack/<tech>.mdfor each selected technologyseh.lock— records the selected technologies (commit it)
Supported technologies: javascript, typescript, python, go, c,
rust, java. No generic fallback — pick at least one.
Then fill in .seh/project.md and .seh/domain/* and re-sync.
seh syncRewrites the project AGENTS.md index and .seh/stack/* from seh.lock.
Idempotent (no change on re-run with unchanged sources).
seh checkExit 0 if the generated files match the sources; exit 1 (with a message) if
AGENTS.md or a stack module is stale or missing. Suitable for pre-commit/CI.
seh link --add claude # symlink ~/.claude/CLAUDE.md -> ~/.seh/AGENTS.md
seh link --remove claude # remove itAGENTS.md stays the single source of truth; symlinks are pure pointers, so
there is no per-agent content to drift.
Supported agents: claude, codex, pi, gemini, opencode, copilot, agents
The agents target manages the cross-agent interoperability path (~/.agents/,
.agents/) used as an alias by Gemini CLI, Pi, Copilot, and others.
| Agent | Target |
|---|---|
claude |
~/.claude/CLAUDE.md |
codex |
~/.codex/AGENTS.md |
pi |
~/.pi/agent/AGENTS.md |
gemini |
~/.gemini/GEMINI.md |
opencode |
~/.config/opencode/AGENTS.md |
copilot |
~/.copilot/copilot-instructions.md |
agents |
~/.agents/AGENTS.md |
| Agent | Target | Canonical |
|---|---|---|
claude |
CLAUDE.md |
.seh/AGENTS.md |
codex |
AGENTS.md |
.seh/AGENTS.md |
pi |
AGENTS.md |
.seh/AGENTS.md |
gemini |
GEMINI.md |
.seh/AGENTS.md |
opencode |
AGENTS.md |
.seh/AGENTS.md |
copilot |
.github/copilot-instructions.md |
.seh/AGENTS.md |
agents |
.agents/AGENTS.md |
.seh/AGENTS.md |
A harness package is a plain directory the user versions with git, carries
between machines, and shares with teammates. seh scaffolds and reads it; git
is fully external and never wrapped.
my-harness/
├── harness.json — package metadata (name, version, modelTag)
├── CHANGELOG.md — harness decisions and reasoning (human-authored)
├── global/
│ ├── AGENTS.md — global ruleset (replaces ~/.seh/AGENTS.md)
│ └── config.json — agent symlink config
├── templates/
│ ├── stack/ — per-technology structural patterns
│ └── project/ — full project scaffolds
├── projects/ — per-repo overlays matched by repo name
└── skills/ — skills to distribute (vendored or referenced)
├── brainstorming/ — vendored skill (committed to package repo)
└── caveman/ — referenced skill (fetched on install)
Scaffolds a new harness package at path (default: ./my-harness). Creates
the full directory structure, copies bundled stack modules as a starting point,
writes harness.json and an empty CHANGELOG.md.
seh package init ~/my-harness
cd ~/my-harness && git init && git add . && git commit -m "init harness"Points seh at an existing package. Writes packagePath into ~/.seh/config.json.
git clone git@github.com:you/my-harness.git ~/my-harness
seh package use ~/my-harnessShows the currently active package path, name/version from harness.json, and
whether each expected directory exists.
Installs artifacts from the active package onto the host machine.
seh package install --harness # write ~/.seh/AGENTS.md + agent symlinks
seh package install --skills # symlink skills into ~/.seh/skills/ + agent dirs
seh package install --all # both of the above
seh package install --all --agents claude,gemini # non-interactive agent selection| Flag | Action |
|---|---|
--harness |
Writes ~/.seh/AGENTS.md from package/global/AGENTS.md; updates agent symlinks |
--skills |
Fetches referenced skills, symlinks package/skills/<name>/ → ~/.seh/skills/<name>/ → agent skill dirs |
--all |
Both of the above |
--agents <list> |
Comma-separated agents to receive skill symlinks (prompts interactively if omitted) |
--force |
Overwrite existing files |
New machine workflow:
git clone git@github.com:you/my-harness.git ~/my-harness
seh package use ~/my-harness
seh package install --allSkills (reusable SKILL.md-based capability packages) are a first-class layer
in the harness package. seh distributes them from the package to every agent
that supports a skill directory.
<package>/skills/<name>/ ← source (vendored or referenced)
↓ symlink
~/.seh/skills/<name>/ ← stable intermediate on this machine
↓ symlinks
~/.claude/skills/<name>/ ← Claude Code
~/.codex/skills/<name>/ ← Codex CLI
~/.gemini/skills/<name>/ ← Gemini CLI
~/.config/opencode/skills/<name>/ ← OpenCode
~/.pi/agent/skills/<name>/ ← Pi
~/.copilot/skills/<name>/ ← GitHub Copilot
~/.agents/skills/<name>/ ← cross-agent interoperability path
~/.seh/skills/ is the stable intermediate: if the package moves, agent
symlinks remain intact until re-pointed.
Adds a skill from a GitHub URL to the active package.
seh skills add https://github.com/JuliusBrussee/caveman --reference
seh skills add github:you/my-skill --vendor --ref v1.2--vendor: clones files into<package>/skills/<name>/(committed to git)--reference: records the URL inharness.jsononly; appendsskills/<name>/to.gitignore; files are fetched at install time- Prompts for type if neither flag is given
- Infers skill name from the repo name
Routing flags tell agents when to invoke the skill. Exactly one may be used:
| Flag | When agent invokes |
|---|---|
--always [label] |
Every response |
--when <condition> |
When the described scenario matches |
--optional |
Agent decides based on context |
seh skills add github:you/caveman --vendor --always "every response"
seh skills add github:you/systematic-debugging --vendor --when "bug / test failure / unexpected behavior"
seh skills add github:you/xlsx --vendor --optionalRouting is stored in harness.json and rendered into a ## Skills section in
both the project AGENTS.md (by seh sync) and the global ~/.seh/AGENTS.md
(by seh package install --harness), so agents always know which skills to
invoke and when.
Re-fetches referenced skill(s) from their source. No arguments updates all referenced skills. Errors if the named skill is vendored.
Shows skills in the active package with their routing mode:
✓ brainstorming [vendor] always: before any implementation
✓ systematic-debugging [vendor] when: bug / test failure
✗ caveman [reference] https://github.com/JuliusBrussee/caveman (ref: main)
✓ xlsx [vendor] optional
✓ = files present on disk, ✗ = reference not yet fetched (run
seh package install --skills to fetch).
{
"name": "my-harness",
"version": "1.0.0",
"skills": {
"brainstorming": {
"type": "vendor",
"invoke": { "mode": "always", "label": "before any implementation" }
},
"systematic-debugging": {
"type": "vendor",
"invoke": { "mode": "when", "condition": "bug / test failure / unexpected behavior" }
},
"caveman": {
"type": "reference",
"source": "https://github.com/JuliusBrussee/caveman",
"ref": "main",
"invoke": { "mode": "always", "label": "every response" }
},
"xlsx": {
"type": "vendor",
"invoke": { "mode": "optional" }
}
}
}The same ## Skills section is appended to the project .seh/AGENTS.md (by
seh sync) and to the global ~/.seh/AGENTS.md (by
seh package install --harness) whenever a skill has routing configured:
## Skills
Always invoke:
- `brainstorming` — before any implementation
- `caveman` — every response
Invoke when:
- `systematic-debugging` — bug / test failure / unexpected behavior
Optional:
- `xlsx`Skills with no invoke field are omitted from this section. If no skills have
routing, the section is omitted entirely.
.seh/memory/ stores typed markdown files that agents read for persistent
project context — decisions made, constraints discovered, learnings earned,
problems still open. Files are committed to the repo so the whole team (and
every agent) shares the same memory.
---
type: decision
---
# Auth strategy
Chose JWT over sessions. Sessions required sticky routing which complicates
the Docker setup. JWT is stateless and works across all replicas.Types:
| Type | When to use |
|---|---|
decision |
A choice made and why (architecture, tech, approach) |
constraint |
A hard rule discovered (never do X, always do Y) |
learning |
Something non-obvious that cost time to figure out |
problem |
Unresolved issue to pick up next session |
Creates .seh/memory/<name>.md with the correct frontmatter and opens
$EDITOR (prints the file path if $EDITOR is unset). Default type is
decision. Does not overwrite an existing file.
seh memory add auth-strategy # type: decision (default)
seh memory add rate-limiting --problem
seh memory add jwt-expiry --learning
seh memory add url-structure --constraintShows all memory files grouped by type:
Decisions
auth-strategy Chose JWT over sessions
db-migrations Use Flyway, not Liquibase
Constraints
url-structure Never expose user IDs in URLs
Learnings
jwt-expiry Access tokens must be short-lived (<15m)
Open problems
rate-limiting Strategy unresolved — Redis vs in-process
Deletes .seh/memory/<name>.md.
seh sync appends a ## Memory section to .seh/AGENTS.md whenever
.seh/memory/ exists. It always includes a protocol block instructing agents
to write memory at session end, plus an index of existing files grouped by type:
## Memory
Write to `.seh/memory/` at end of every session:
- **decision** — a choice made and why (architecture, tech, approach)
- **constraint** — a hard rule discovered (never do X, always do Y)
- **learning** — something non-obvious that cost time to figure out
- **problem** — unresolved issue to pick up next session
Run: `seh memory add <name> [--decision|--constraint|--learning|--problem]`
### Decisions
- [Auth strategy](.seh/memory/auth-strategy.md) — Chose JWT over sessions
### Open problems
- [Rate limiting](.seh/memory/rate-limiting.md) — Strategy unresolvedIf .seh/memory/ is empty the protocol block is still rendered (so new agents
know how to populate it). If the directory doesn't exist the section is omitted.
All supported agents have confirmed user-level skill directories (as of 2026-07):
| Agent | User skill directory |
|---|---|
claude |
~/.claude/skills/<name> |
codex |
~/.codex/skills/<name> |
gemini |
~/.gemini/skills/<name> |
opencode |
~/.config/opencode/skills/<name> |
pi |
~/.pi/agent/skills/<name> |
copilot |
~/.copilot/skills/<name> |
agents |
~/.agents/skills/<name> |
seh is distributed from GitHub — no npm registry account needed.
One command installs a self-contained build (deps bundled) and puts seh on
your PATH — no npm, no build step, no global node_modules:
curl -fsSL https://raw.githubusercontent.com/manuuuel/seh/main/scripts/install.sh | sh- Update: re-run the same command.
- Pin a version:
curl -fsSL .../scripts/install.sh | SEH_REF=v0.4.1 sh - Installs to
~/.local/share/seh, symlinks~/.local/bin/seh(override viaSEH_HOME/SEH_BIN). Requiresnodeon PATH. - Uninstall:
rm -rf ~/.local/share/seh ~/.local/bin/seh
npm install -g github:manuuuel/seh # latest main
npm install -g github:manuuuel/seh#v0.4.1 # a tagnpm installs go through npm's git-dep preparation, which can fail with ENOTDIR
if a previous global install left a broken entry. If that happens, remove the
stale .../lib/node_modules/se-harness, run npm cache clean --force, and retry
— or just use the curl installer above, which avoids npm entirely.
git clone git@github.com:manuuuel/seh.git ~/pocs/seh
cd ~/pocs/seh
npm install
npm run build
npm link # makes `seh` available in $PATHTo uninstall: npm unlink -g se-harness.
npm install --save-dev github:manuuuel/seh
npx seh initRuns the whole flow against a throwaway HOME — your real ~/.seh and
~/.claude are untouched:
npm run trynpm install
npm run build # compile to dist/
npm test # run the test suite (155 tests)
npm run dev # run the CLI via tsx without building