Install
$ agentstack add skill-junhanliu-dev-espalier-engineering-espalier-init ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Espalier Init
Discover the actual patterns, conventions, and architecture of an existing codebase, then generate a structured constraint system that ensures AI agents produce code matching those standards.
When to Use
- "Set up Espalier for this project"
- "Create Espalier structure for my codebase"
- "Make AI code production-ready for this repo"
- "Build agent constraints for this project"
- "/espalier-init"
Philosophy
> When an agent makes an error, engineer its elimination — not with prompt tweaks, but with files, rules, automated checks, and system structure.
Core insight: The problem isn't model intelligence. It's that models don't know the unwritten rules — patterns every experienced developer on the team knows but nobody documented.
This skill discovers those rules from the code itself, then encodes them as machine-enforceable constraints. Like an espalier trains a fruit tree to grow along a wall, this skill trains your AI coder to grow along the patterns already in your codebase.
File Layout of This Skill
espalier-init/
├── SKILL.md # this file — overview + phase index
├── templates/ # markdown templates emitted into target project
│ ├── rules/ # → espalier/rules/ in target
│ ├── skills/ # → espalier/skills//SKILL.md
│ ├── agents/ # → espalier/agents/ in target
│ ├── agent.md # → espalier/agent.md (orchestrator)
│ └── pipeline.md # → espalier/pipeline.md
├── hook-templates/ # shell scripts emitted into espalier/hooks/
└── references/ # deep-dive content read on demand
├── discovery-checklist.md # Phase 1 detail
├── wiring.md # Phase 10 detail
├── validation.md # Phase 11 detail
└── wiki-templates.md # Phase 6 wiki stubs
Rule: Every phase below tells you which template/reference to read. Open them with the Read tool when the phase fires — do NOT invent template content from memory.
Output Structure in Target Project (after full setup)
project-root/
├── .claude/
│ ├── rules/ # symlinks to espalier/rules/*.md
│ ├── skills/ # symlinks to espalier/skills/*
│ ├── agents/ # symlinks to espalier/agents/*.md
│ └── settings.json # hooks for quality gates
├── CLAUDE.md # references espalier/agent.md
├── espalier/
│ ├── agent.md # orchestrator definition
│ ├── rules/ # engineering-structure, coding-standards, development-process
│ ├── skills/ # folder name MUST equal SKILL.md `name:` frontmatter
│ │ ├── espalier-coding/
│ │ │ ├── SKILL.md
│ │ │ └── specs/{layer}.md
│ │ ├── espalier-review/SKILL.md
│ │ ├── espalier-testing/SKILL.md
│ │ ├── espalier-requirements/SKILL.md
│ │ ├── espalier-grill/SKILL.md # Stage 1 interrogation (invoked by espalier + espalier-fix)
│ │ ├── espalier/SKILL.md # main pipeline orchestrator (slash: /espalier)
│ │ ├── espalier-fix/SKILL.md # bug-fix lane (5-stage; slash: /espalier-fix)
│ │ ├── espalier-prune/SKILL.md # stale-artifact refresh (slash: /espalier-prune)
│ │ ├── espalier-doctor/SKILL.md # periodic drift scan (slash: /espalier-doctor)
│ │ └── espalier-ask/SKILL.md # read-only Q&A lane (slash: /espalier-ask)
│ ├── agents/ # harness-coder.md, harness-reviewer.md (agent names kept for stability)
│ ├── wiki/ # architecture, data-models, critical-paths, external-services
│ ├── hooks/ # check-layer-boundaries.sh, pre-push-gate.sh
│ ├── pipeline.md
│ └── changes/ # typed: feat/, fix/, refactor/, …
│ ├── _template/ # requirements.md, task-breakdown.md, coding-report.md, review-record.md, pipeline-state.md, ci-result.md
│ ├── feat/{slug}/ # full pipeline outputs ({slug} = YYYY-MM-DD-, sorts chronologically)
│ ├── fix/{slug}/ # fix-lane outputs (with caused_by frontmatter)
│ └── refactor/{slug}/ # (future)
└── src/ (existing code)
Skill Naming Invariant (CRITICAL — read before creating any skill)
Claude Code's skill loader compares the folder name against the SKILL.md name: frontmatter. If they differ, the skill emits a warning and may fail to register.
Rule: every skill folder MUST be named identically to its name: frontmatter value.
✅ CORRECT
espalier/skills/espalier-coding/SKILL.md (name: espalier-coding)
espalier/skills/espalier-review/SKILL.md (name: espalier-review)
espalier/skills/espalier/SKILL.md (name: espalier) ← main pipeline
❌ WRONG (will warn / break)
espalier/skills/coding/SKILL.md (name: espalier-coding)
espalier/skills/review/SKILL.md (name: espalier-review)
When you generate a skill:
- Choose the
name:value first (must be globally unique, kebab-case, descriptive — prefix withespalier-for child skills inside this install; the main pipeline owns the bare nameespalier). - Use the SAME string as the folder name.
- Symlinks in
.claude/skills/then resolve to a same-named source folder — no mismatch possible.
This applies to all skill folders generated by this skill: espalier-coding, espalier-review, espalier-testing, espalier-requirements, espalier-grill, espalier (main), espalier-fix, espalier-prune, espalier-doctor, espalier-ask, and any additional ones added later.
Phase Dependency Note (parallel execution)
Phases 0-2 are sequential by necessity (Phase 0 prompt blocks; Phase 1 produces DISCOVERY blob consumed by Phase 2). Within Phase 1 and Phase 2, work is parallel. Phases 3+ are bundled into a single bootstrap-espalier.sh invocation.
Rule: run Phases 0 → 1 → 2 → 3 in order. Each step batches parallel work to minimize sequential tool calls (~5-7 batched turns total).
Phase 0: Setup Decisions (front-loaded)
Issue ONE AskUserQuestion with THREE questions in the multi-question form:
Q1 — Squash-merge strategy
How does this repo merge PRs? Choice affects how /espalier-fix links bug
fixes to causing commits.
1. Rebase-merge / true merge-commit → MERGE_DECISION = not-needed
SHAs preserved; no special handling needed.
2. Squash + install post-merge hook (recommended) → MERGE_DECISION = installed
Hook records original→squashed SHA so fix lane finds origin via O(1) lookup.
3. Squash + allow fuzzy match at fix-time → MERGE_DECISION = fuzzy-allowed
No hook. Fix lane falls back to file-overlap heuristic. Less safe.
4. Squash + skip linking when SHA misses (safest) → MERGE_DECISION = skip-only
No hook, no fuzzy. Fix proceeds without causal link if SHA unresolvable.
5. Squash + never ask again, always skip → MERGE_DECISION = never-ask
Same as skip-only but suppresses future "what should I do" prompts.
6. Decide later → MERGE_DECISION = ask-later
Defer. Fix lane will prompt the first time SHA resolution fails.
Q2 — Sub-agent tool access
Generated sub-agents (harness-coder, harness-reviewer) declare a `tools:`
field in their frontmatter that restricts what they can call. Pick the
scope for this install:
1. Restricted (recommended, default) → AGENT_TOOLS = restricted
Templates' minimal tool list:
harness-coder → Read, Write, Edit, Bash, Glob, Grep
harness-reviewer → Read, Grep, Glob, Bash
Safest. Sub-agents can't reach MCPs, plugins, web search, Task spawning.
2. Inherit from parent session → AGENT_TOOLS = inherit
Drop the `tools:` frontmatter field entirely. Sub-agents inherit
every tool available to the calling Claude Code session — MCPs,
plugins, custom skills, WebFetch, etc.
Useful when target project relies on MCPs (e.g., database query,
internal API access) and review/coding needs them. Broader blast
radius — reviewer could in principle make external calls.
Q3 — Doctor cadence
How often should /espalier-doctor re-scout the codebase for artifact drift?
A doctor scan is activity-gated — an idle repo never triggers one.
1. Every change → DOCTOR_CADENCE = every-change
Checked at every pipeline Stage 0. Thorough; noisiest.
2. Weekly (recommended) → DOCTOR_CADENCE = weekly
First pipeline activity after 7 days triggers a scan.
3. Monthly → DOCTOR_CADENCE = monthly
First pipeline activity after 30 days triggers a scan.
4. On-demand only → DOCTOR_CADENCE = manual
Never automatic; runs only when you invoke /espalier-doctor.
> Why agent identifiers stay harness-coder / harness-reviewer: these are internal sub-agent names baked into pipeline orchestration. Renaming them mid-pipeline would break any in-flight changes. The plugin name and slash commands rebranded to Espalier in v0.4.0; agent identifiers remain frozen.
Cache the answers in $MERGE_DECISION, $AGENT_TOOLS, and $DOCTOR_CADENCE. Phase 2's Write batch reads $AGENT_TOOLS when emitting espalier/agents/harness-coder.md and espalier/agents/harness-reviewer.md:
restricted→ keep thetools:frontmatter line from the template verbatiminherit→ omit thetools:line entirely (Claude Code interprets missingtools:as "inherit from parent")
Pass $MERGE_DECISION and $DOCTOR_CADENCE to bootstrap-espalier.sh in Phase 3 (--merge-decision=$MERGE_DECISION --doctor-cadence=$DOCTOR_CADENCE). $AGENT_TOOLS only affects Phase 2 LLM writes, no bootstrap flag needed.
Phase 1: Discovery (parallel — single message)
Issue ONE message with up to 10 parallel tool calls:
- Bash batch (1.1 + 1.5):
tldr tree && tldr arch && tldr structure && ls package.json go.mod pyproject.toml Cargo.toml Gemfile pom.xml 2>/dev/null && ls .github/workflows Jenkinsfile Makefile justfile 2>/dev/null && git log --oneline -20 - scout (1.2 — architecture): layers, dep directions, boundary table
- scout (1.3 — coding patterns): read 5-8 source files; naming/errors/async/types/logging/validation
- scout (1.4 — testing): read 2-3 test files; framework + mock pattern
- scout (1.5 — git + CI): branch strategy, commit conventions, CI checks (build/lint/test commands)
- scout (1.6 — unwritten rules): compare 3+ files of same type per layer; invariants + anti-patterns
- oracle (1.7 — best practices): ctx7 lookup AND web search fired in parallel for the detected stack. Synthesize both results. Divergence notes.
- scout (1.8 — data models, wiki): schemas, migrations, model classes, relationships
- scout (1.9 — critical paths, wiki): entry points, primary flows, modification hotspots
- scout (1.10 — external services, wiki): SDK imports, env vars, services, timeout/retry patterns
Read first: references/discovery-checklist.md — exact scout prompts to paste.
Each scout returns:
{ "scout_id": "1.N", "status": "ok"|"no_evidence", "summary": "≤200w", "structured": {...}, "evidence_files": [...] }
After all scouts return:
- If any returned
status: no_evidence, batch into ONE follow-upAskUserQuestion(per layer/scout: skip / provide files / mark not-applicable). Don't ask N times. - Merge all
status: okoutputs into in-contextDISCOVERYblob (no disk write).
Phase 2: Substitution Writes (parallel — single message)
Issue ONE message with parallel Write calls, all sourcing from DISCOVERY:
Rules (3 files):
espalier/rules/engineering-structure.md←templates/rules/engineering-structure.md+ DISCOVERY.layers/.namingespalier/rules/coding-standards.md←templates/rules/coding-standards.md+ DISCOVERY.{naming,error_handling,…}espalier/rules/development-process.md←templates/rules/development-process.md+ DISCOVERY.{branchstrategy,commitconventions,ci_checks}
Orchestrator + per-stack skills (4 files):
espalier/agent.md←templates/agent.md+ project_name + DISCOVERY.{lang,framework,layers}espalier/skills/espalier-coding/SKILL.md←templates/skills/espalier-coding.md+ DISCOVERYespalier/skills/espalier-testing/SKILL.md←templates/skills/espalier-testing.md+ DISCOVERY.testingespalier/skills/espalier-review/SKILL.md←templates/skills/espalier-review.md(swap{project}→ project_name)
Sub-agents (2 files — tools: field branches on $AGENT_TOOLS from Phase 0 Q2):
espalier/agents/harness-coder.md←templates/agents/harness-coder.md+ project_name. If$AGENT_TOOLS == restricted(default): keeptools: Read, Write, Edit, Bash, Glob, Grepline. If$AGENT_TOOLS == inherit: omit thetools:line entirely so the agent inherits from parent session.espalier/agents/harness-reviewer.md←templates/agents/harness-reviewer.md+ project_name. Same branching: keeptools: Read, Grep, Glob, Bashfor restricted; omit for inherit.
Wiki (4 files — all populated from DISCOVERY scouts 1.2/1.8/1.9/1.10, never stubs):
espalier/wiki/architecture.md← DISCOVERY.architecture (scout 1.2)espalier/wiki/data-models.md← DISCOVERY.data_models (scout 1.8)espalier/wiki/critical-paths.md← DISCOVERY.critical_paths (scout 1.9)espalier/wiki/external-services.md← DISCOVERY.external_services (scout 1.10)
Hooks with placeholders (2 files):
espalier/hooks/pre-push-gate.sh←hook-templates/pre-push-gate.sh, swap{build_command}/{lint_command}/{test_command}from DISCOVERY.ci_checksespalier/hooks/check-layer-boundaries.sh←hook-templates/check-layer-boundaries-${LANG}.sh, rewritecaseblock from DISCOVERY.layers. If LANG ∉ {ts,py,go}, emit a no-op script (#!/bin/bash\nexit 0).
Then per-layer specs (parallel scout batch + Write batch):
For each layer in DISCOVERY.layers where a spec is warranted (non-trivial file template, distinct import rules, or layer-specific anti-patterns):
Issue ONE message with N parallel scout calls:
scout("Read 2-3 representative files in . Return JSON:
{ layer_name, template_skeleton: ,
allowed_imports: [...], forbidden_imports: [...], example_file_path }")
After all scouts return, issue ONE parallel Write batch for espalier/skills/espalier-coding/specs/{layer}.md files. Skip layers flagged trivial (e.g., bare index.ts re-export barrel).
Spec template (templates/skills/espalier-coding-spec.md) has no frontmatter — specs are sub-pages of espalier-coding, not registered skills.
Phase 3: Bootstrap (one bash invocation)
Run:
# ${CLAUDE_SKILL_DIR} is this skill's directory (/skills/espalier-init).
# bootstrap-espalier.sh sits at the plugin root (../../scripts/); its
# --plugin-dir wants the dir holding hook-templates/ + templates/ — which is
# this skill's own directory. Resolves the installed plugin in any layout.
bash "${CLAUDE_SKILL_DIR}/../../scripts/bootstrap-espalier.sh" \
--project-dir=. \
--plugin-dir="${CLAUDE_SKILL_DIR}" \
--lang=$LANG \
--merge-decision=$MERGE_DECISION \
--doctor-cadence=$DOCTOR_CADENCE
Bootstrap runs all 11 internal stages in one shell process:
- Stages 1-2: preflight +
mkdir -p(idempotent — Phase 2 Writes already created some dirs). - Stage 3:
cppure-copy templates →espalier/pipeline.md, `espalier/skills/{espalier,espalier-fix,espalier-requirements,espalier-grill,espalier-prune
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Junhanliu-dev
- Source: Junhanliu-dev/espalier-engineering
- License: MIT
- Homepage: https://junhanliu-dev.github.io/espalier-engineering/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.