Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
- `skills/GuardRails/DestructiveCommandGuard.md` companion (dcg block anatomy and workarounds), `skills/IncrementalEdits/` (revise files as reviewable hunks), `skills/SessionSearch/LocalCheckpoints.md`; updates to SettingsMaintenance, SystemCheck, Wtf, ProvenanceAudit, and the ProvenanceAuditor agent
- `skills/InitProject/` — `project` / `atlas` shell functions that scaffold a workshop project spine (git + jj colocate + entire + forge hooks, private/public/assets flow, `.tlp` manifest, vault-mounted `.claude/`) with on-demand satellites (vault folder-note, `~/Data` domain-path mirror granted to agent sessions, private remote). Config in `~/.config/forge/project.yaml` with `FORGE_*` per-shell overrides; `project init` renders `CLAUDE.md.tmpl` into each project's brief
- `.githooks/` gains `commit-msg`, `prepare-commit-msg`, `post-commit`, `post-rewrite`, and the pre-entire `pre-push` variant, completing the commit-gate set that `make install` wires via `core.hooksPath`; `BACKLOG.md` tracks module-level follow-ups
- `skills/ForgeSkill/` — BuildSkill's router and companions merged with the eval machinery adopted from [anthropics/skills](https://github.com/anthropics/skills) skill-creator (grader/comparator/analyzer agents, eval and description-optimization scripts, browser viewer), pinned per-file by SLSA provenance sidecars (Apache-2.0 under EUPL-1.2). New companions `EvalLoop.md` and `DescriptionOptimization.md` route the test-improve-iterate loop and trigger optimization. BuildSkill remains until the artifact-merge analysis lands
- `skills/BashConventions/` + `BashPatterns.md` companion — Bash pitfalls (BSD vs GNU, `set -euo pipefail` traps, subprocess env) relocated from forge-dev
- `skills/VersionControl/GitWorktrees.md` — companion covering parallel feature work via `git worktree`, with SLSA provenance (adapted from [davila7/claude-code-templates](https://github.com/davila7/claude-code-templates) MIT under EUPL-1.2)
- `VersionControl` now serves as the canonical home for git conventions and platform-specific repo governance (absorbing the retired forge-dev `Git` skill). forge-dev's `GitHub` skill remains distinct — it covers CI, Actions, releases, and operational `gh` workflows
Expand Down
10 changes: 2 additions & 8 deletions skills/BuildSkill/ClaudeSkill.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,6 @@ Claude Code discovers skills through `plugin.json`:

Every directory listed is scanned for `*/SKILL.md` files. Skills in later directories override earlier ones of the same name (last wins).

## Skill Load Hooks
## Dynamic context injection (`!`)

Skills can execute shell commands on load using `!` backtick lines at the end of SKILL.md:

```markdown
!`some-command arg1 arg2`
```

These run when the skill is invoked. Use for loading additional context, checking prerequisites, or initializing state.
A Claude skill can open with live machine state via `` !`<command>` `` lines in the SKILL.md body, the output runs and is substituted before Claude sees the content. This is a first-class authoring concern with its own guide: **[@DynamicContextInjection.md](DynamicContextInjection.md)**. Reach for it whenever a skill's job starts with orienting on current state.
1 change: 1 addition & 0 deletions skills/BuildSkill/CreateWorkflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Follow the structure from [SkillStructure.md](SkillStructure.md).
- [ ] Frontmatter has `name:` and `description:` with `USE WHEN`
- [ ] Description is single-line, under 1024 characters
- [ ] Body starts with `# SkillName` heading
- [ ] **For a Claude skill, decide what live state to inject.** Ask what current machine state would orient the model on load (branch, tool status, the names of things), and open the body with a `!` injection of it. Default to injecting unless there is a reason not to; see [DynamicContextInjection.md](DynamicContextInjection.md)
- [ ] Clear step-by-step instructions (numbered steps for sequential operations)
- [ ] If wrapping a CLI tool: usage examples, intent-to-flag mapping, output format (see [CliToolIntegration.md](CliToolIntegration.md))
- [ ] Constraints section with boundary conditions
Expand Down
48 changes: 48 additions & 0 deletions skills/BuildSkill/DynamicContextInjection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Dynamic context injection (`!`)

A Claude Code skill can open with **live machine state** instead of stale prose. `` !`<command>` `` lines in the SKILL.md body run when the skill is invoked, and their output replaces the placeholder before Claude sees the content ("Inject dynamic context", a Claude Code extension to the Agent Skills standard).

When authoring a Claude skill, treat this as a first-class step, not an afterthought: **ask what live state would orient the model on load, and inject it.** A skill that opens with the actual situation (the current branch and diff, a tool's auth status, the names of things that exist right now) beats one that only describes how to go find it. Default to injecting unless there is a reason not to.

```markdown
---
name: MySkill
description: ...
allowed-tools: Bash(git status *) Bash(git diff *)
---

# MySkill

Current branch and changes:

!`git status --short 2>/dev/null || echo "(not a git repo)"`
```

Each `` !`<command>` `` runs once, before the rendered SKILL.md is sent to Claude; the output replaces the placeholder inline. Substitution is single-pass: injected output is not re-scanned for further placeholders.

## Hard constraints (verified by running it, not just the docs)

- **SKILL.md body only.** `!` executes only in the SKILL.md body, never in `@`-companion files (those load as plain text). Put every injected command in SKILL.md and keep companions as reference prose.
- **`allowed-tools` is required.** List the Bash scopes the injected commands need in the SKILL.md frontmatter, e.g. `allowed-tools: Bash(pass *) Bash(git *)`. It is a frontmatter field in SKILL.md itself (space-, comma-, or list-separated); there is no sidecar location. (Note: `forge assemble` currently strips it for the Claude provider, forge-cli#69, until fixed, a forge-deployed skill loses the field.)
- **No shell expansions.** The injection rejects any command containing `$(...)`, `${...}`, or backticks with a `Contains expansion` error. Keep injected commands simple and static; a guarded summary that needs command substitution will not run, inject the raw command output instead.
- **No built-in error handling.** A failing command does not degrade gracefully; it breaks or blanks the injection. Self-guard every command so a missing tool, logged-out session, or empty result cannot break skill load:

```markdown
!`pass-cli vault list 2>/dev/null || echo "(proton pass: not logged in)"`
```

- **Claude Code only.** `!`, `@`, and `$ARGUMENTS` are Claude Code extensions, not part of the portable Agent Skills standard. In Codex / Gemini / opencode the `!` lines render as inert literal text. Use injection in skills you accept as Claude-first; it degrades to harmless text elsewhere.

## Substitutions available alongside `!`

`$ARGUMENTS`, `$ARGUMENTS[N]`, `$N`, `$name` (named args), and `${CLAUDE_SESSION_ID}` / `${CLAUDE_EFFORT}` / `${CLAUDE_SKILL_DIR}` are substituted in the SKILL.md body the same way.

## What to inject, and what never to

Inject **read-only, fast, structural state** that orients Claude: the current branch, a file listing, a tool's status, the names of things. Never inject:

- **Secret values.** For a credential skill, inject the *map* (entry names, vault list, auth status), never the *territory*. `` !`pass ls` `` is fine (entry names); `` !`pass show <x>` `` is forbidden, it would dump a live secret into the transcript and context.
- **Slow or interactive commands.** Injection blocks skill load; a command that prompts, hangs, or takes seconds makes the skill feel broken.
- **Mutating commands.** Injection should observe, not change state.

The litmus test: if the command's output appearing verbatim in the session transcript would be a problem, do not inject it.
5 changes: 5 additions & 0 deletions skills/BuildSkill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ Create and validate skills following forge conventions. Skills are markdown file
| Topic | Companion |
| ----------------------------------------------------------- | -------------------------------------------------------- |
| SKILL.md structure, frontmatter, body layout, naming | [@SkillStructure.md](SkillStructure.md) |
| **Dynamic context injection (`!`): open a Claude skill with live state** | [@DynamicContextInjection.md](DynamicContextInjection.md) |
| Multi-provider routing via `defaults.yaml` | [@MultiProviderRouting.md](MultiProviderRouting.md) |
| Wrapping a CLI tool in a skill | [@CliToolIntegration.md](CliToolIntegration.md) |
| Platform-agnostic writing — no placeholders or `/` prefix | [@PlatformAgnostic.md](PlatformAgnostic.md) |
| User-config schema for AI-first artifacts (autoMode mirror) | [@UserConfigSchema.md](UserConfigSchema.md) |
| Claude-only features: `@` refs, skill discovery, `allowed-tools` | [@ClaudeSkill.md](ClaudeSkill.md) |
| When to author a per-skill INSTALL.md | [@SkillInstallation.md](SkillInstallation.md) |

## Red Flags
Expand All @@ -36,6 +38,9 @@ Create and validate skills following forge conventions. Skills are markdown file
| "Leave a stub section as a placeholder" | Skill bodies are plain prose. Delete empty sections, don't scaffold them. |
| "Inline every example in the SKILL.md" | SKILL.md should stay slim. Move static reference material to companion files. |
| "Skill directory can have any name" | Directory name must match the `name:` frontmatter field exactly. |
| "Put a `!` injection in a companion file" | `!` runs only in the SKILL.md body; in a companion it renders as literal text. See [@ClaudeSkill.md](ClaudeSkill.md). |
| "Inject a secret value with `!` (e.g. `pass show`)" | Injection lands in the transcript. Inject structure/status (names, vault list), never secret values. |
| "It ran in my sandbox, so the probe is done" | Your sandbox has tooling (uv, personal paths, aliases) the target machine lacks — resolve interpreters at preflight and assume a clean environment. |

## Constraints

Expand Down
52 changes: 52 additions & 0 deletions skills/BuildSkill/UserConfigSchema.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# User Config Schema (autoMode mirror)

When an artifact needs per-user runtime data, follow the [UserConfig](../../rules/UserConfig.md) rule — one file per artifact at `~/.config/forge/<artifact>.{ext}`. When the config is intended to be read by an AI in the loop (skill, agent, or hook with model access), shape it after [Claude Code's `autoMode`][AM]: natural-language entries with a four-tier precedence model and a `$defaults` splice token.

## Why mirror autoMode

The pattern is already familiar to anyone configuring Claude Code. Entries are prose — descriptions a human (or AI) would naturally write — not regex or tool-pattern grammars. The `$defaults` token gives a splice-or-replace toggle for built-in defaults shipped with the artifact source. Users extend the built-ins by adding entries; they take full ownership by omitting `"$defaults"`.

## Shape

Top-level keys are tiers with strict precedence: `hard_deny` > `soft_deny` > `allow` > `environment`. Each value is an array of prose strings.

```yaml
environment:
- "$defaults"
- "<who I am and where I work>"

allow:
- "$defaults"
- "<exceptions to soft_deny — surfaces that are intentional>"

soft_deny:
- "$defaults"
- "<rules the user can override with explicit intent>"

hard_deny:
- "$defaults"
- "<rules that cannot be overridden>"
```

## Tier semantics

- `hard_deny` blocks unconditionally. No `allow` exception or user intent applies.
- `soft_deny` blocks next. `allow` exceptions and explicit user intent can override.
- `allow` overrides matching `soft_deny` entries.
- `environment` provides context: trusted infrastructure, identities, repo ownership.

Setting any tier without `"$defaults"` replaces the entire built-in list for that tier. Default entries are spliced at the position of the token, so custom entries can go before or after them.

## When NOT to use this pattern

Deterministic consumers (shell scripts, pre-commit hooks, CI gates without model access) can't interpret prose. Ship a sibling artifact for those — same `~/.config/forge/` directory, different filename — with a flat regex list or other machine-readable structure. Don't try to mix prose and regex in one file; the consumer types diverge.

Example pairing: `~/.config/forge/forensic.yaml` (prose, read by ForensicAgent) and `~/.config/forge/danger-strings` (regex, read by the pre-commit hook).

## Discovery and inspection

The artifact source documents its built-in `$defaults` inline (in `SKILL.md` body or the agent body) so users can read what they inherit before extending. A `forge <artifact> config` subcommand printing the effective merged config is recommended but not required.

## Reference

[AM]: https://code.claude.com/docs/en/auto-mode-config "Claude Code: Configure auto mode"
9 changes: 8 additions & 1 deletion skills/BuildSkill/ValidateWorkflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ Read the SKILL.md file.
- [ ] Intent-to-flag mapping table (if tool has flags)
- [ ] Output format described

## Step 5: Report
## Step 5: Check content quality

- [ ] Inputs and outputs stated explicitly (what the skill consumes, what artifact it produces)
- [ ] Guardrails pause rather than auto-escalate — no silent jump from read-only analysis to executing targets or installing tooling
- [ ] No authoring-environment fingerprints: stdlib-only probes use a preflight-resolved `python3`, not `uv run python`; no personal paths, package managers, or aliases the target machine may lack
- [ ] Deliverable is an artifact (table, file, verdict schema), not prose

## Step 6: Report

**COMPLIANT** — all checks pass.

Expand Down
32 changes: 32 additions & 0 deletions skills/ForgeSkill/.provenance/DescriptionOptimization.md.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
provenance:
_type: https://in-toto.io/Statement/v1
subject:
- name: skills/ForgeSkill/DescriptionOptimization.md
digest:
sha256: f6bd7a7d74423620cf792c87d3add8055949f13ffd6ea2d83d9fd58e0df48e3d
predicateType: https://slsa.dev/provenance/v1
predicate:
buildDefinition:
buildType: https://forge-cli/adopt/v1
externalParameters:
upstream_url: https://github.com/anthropics/skills/blob/b9e19e6f44773509fbdd7001d77ff41a49a486c1/skills/skill-creator/SKILL.md
resolvedDependencies:
- name: upstream
uri: https://github.com/anthropics/skills/blob/b9e19e6f44773509fbdd7001d77ff41a49a486c1/skills/skill-creator/SKILL.md
digest:
sha256: dcd4803e61e913e6fc27294184cd3a71f09f5e924ff20c8a9a20173e7b3c2bcf
- name: AdoptArtifact
uri: forge-core/skills/AdoptArtifact/SKILL.md
digest:
sha256: 722d5e82ebc093749d170b4b5c650ca523e21a52a6079bfabd912613379c1c02
- name: RefinePrompt
uri: forge-core/skills/RefinePrompt/SKILL.md
digest:
sha256: d04d2610148eb9ec2589cd521f1214b6a11d033600335c0295f2fc7a472ca87c
runDetails:
builder:
id: forge-cli
version:
forge: 0.3.2
metadata:
startedOn: 2026-07-08T01:26:42Z
32 changes: 32 additions & 0 deletions skills/ForgeSkill/.provenance/EvalLoop.md.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
provenance:
_type: https://in-toto.io/Statement/v1
subject:
- name: skills/ForgeSkill/EvalLoop.md
digest:
sha256: 135a0897e42e517d5d32959a3e7083e2c274e49393fe0d41fcea717334d295ae
predicateType: https://slsa.dev/provenance/v1
predicate:
buildDefinition:
buildType: https://forge-cli/adopt/v1
externalParameters:
upstream_url: https://github.com/anthropics/skills/blob/b9e19e6f44773509fbdd7001d77ff41a49a486c1/skills/skill-creator/SKILL.md
resolvedDependencies:
- name: upstream
uri: https://github.com/anthropics/skills/blob/b9e19e6f44773509fbdd7001d77ff41a49a486c1/skills/skill-creator/SKILL.md
digest:
sha256: dcd4803e61e913e6fc27294184cd3a71f09f5e924ff20c8a9a20173e7b3c2bcf
- name: AdoptArtifact
uri: forge-core/skills/AdoptArtifact/SKILL.md
digest:
sha256: 722d5e82ebc093749d170b4b5c650ca523e21a52a6079bfabd912613379c1c02
- name: RefinePrompt
uri: forge-core/skills/RefinePrompt/SKILL.md
digest:
sha256: d04d2610148eb9ec2589cd521f1214b6a11d033600335c0295f2fc7a472ca87c
runDetails:
builder:
id: forge-cli
version:
forge: 0.3.2
metadata:
startedOn: 2026-07-08T01:26:42Z
32 changes: 32 additions & 0 deletions skills/ForgeSkill/.provenance/SKILL.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
provenance:
_type: https://in-toto.io/Statement/v1
subject:
- name: skills/ForgeSkill/SKILL.md
digest:
sha256: 92201e60243b40081f9e4853fbac262e3a04321e372626a6b145c671ed42792b
predicateType: https://slsa.dev/provenance/v1
predicate:
buildDefinition:
buildType: https://forge-cli/adopt/v1
externalParameters:
upstream_url: https://github.com/anthropics/skills/blob/b9e19e6f44773509fbdd7001d77ff41a49a486c1/skills/skill-creator/SKILL.md
resolvedDependencies:
- name: upstream
uri: https://github.com/anthropics/skills/blob/b9e19e6f44773509fbdd7001d77ff41a49a486c1/skills/skill-creator/SKILL.md
digest:
sha256: dcd4803e61e913e6fc27294184cd3a71f09f5e924ff20c8a9a20173e7b3c2bcf
- name: AdoptArtifact
uri: forge-core/skills/AdoptArtifact/SKILL.md
digest:
sha256: 722d5e82ebc093749d170b4b5c650ca523e21a52a6079bfabd912613379c1c02
- name: RefinePrompt
uri: forge-core/skills/RefinePrompt/SKILL.md
digest:
sha256: d04d2610148eb9ec2589cd521f1214b6a11d033600335c0295f2fc7a472ca87c
runDetails:
builder:
id: forge-cli
version:
forge: 0.3.2
metadata:
startedOn: 2026-07-08T01:26:42Z
Loading
Loading