Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
b01bdc3
feat(skills): adding skills for writing skills + rewrite
zanjonke Jul 15, 2026
306f00f
feat(skills): add workflow self-check checklists to forge-plain, add-…
zanjonke Jul 15, 2026
daad3aa
feat(break-down-func-spec): add Strategy 6 for extracting technical c…
zanjonke Jul 16, 2026
b24946b
feat(analyze-if-func-spec-too-complex): flag implied technical compon…
zanjonke Jul 16, 2026
3a6db08
docs(add-functional-spec): standardize .plain example formatting (sec…
zanjonke Jul 16, 2026
50734db
docs(add-functional-specs): standardize .plain example formatting (se…
zanjonke Jul 16, 2026
c1832aa
docs(create-import-module): standardize .plain example formatting (se…
zanjonke Jul 16, 2026
22a59dd
docs(create-requires-module): standardize .plain example formatting (…
zanjonke Jul 16, 2026
2677b5a
docs(add-concept): standardize .plain example formatting; keep BAD bl…
zanjonke Jul 16, 2026
7112199
docs(add-implementation-requirement): standardize .plain example form…
zanjonke Jul 16, 2026
0a5e9b3
docs(add-test-requirement): standardize .plain example formatting; ke…
zanjonke Jul 16, 2026
4b39c10
docs(resolve-spec-conflict): standardize .plain example formatting (s…
zanjonke Jul 16, 2026
ed71c99
docs(rules): document the .plain example presentation convention (sec…
zanjonke Jul 16, 2026
287a905
feat(specs): functional specs written as present-tense facts, not imp…
zanjonke Jul 16, 2026
7b8f4fc
feat(forge-plain): delegate phase-gate validation to a one-shot revie…
zanjonke Jul 16, 2026
555239d
fix(resources): linked-resource paths resolve from the codeplain run …
zanjonke Jul 16, 2026
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
45 changes: 45 additions & 0 deletions .claude/skills/skill-creator/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
name: skill-creator
description: Authors and structures professional-grade agent skills following the agentskills.io spec. Use when creating new skill directories, drafting procedural instructions, or optimizing metadata for discoverability. Don't use for general documentation, non-agentic library code, or README files.
---

# Skill Authoring Procedure

Follow these steps to generate a skill that adheres to the agentskills.io specification and progressive disclosure principles.

## Step 1: Initialize and Validate Metadata
1. Define a unique `name`: 1-64 characters, lowercase, numbers, and single hyphens only.
2. Draft a `description`: Max 1,024 characters, written in the third person, including negative triggers.
3. **Execute Validation Script:** Run the validation script to ensure compliance before proceeding:
`python3 scripts/validate-metadata.py --name "[name]" --description "[description]"`
4. If the script returns an error, self-correct the metadata based on the `stderr` output and re-run until successful.

## Step 2: Structure the Directory
1. Create the root directory using the validated `name`.
2. Initialize the following subdirectories:
* `scripts/`: For tiny CLI tools and deterministic logic.
* `references/`: For flat (one-level deep) context like schemas or API docs.
* `assets/`: For output templates, JSON schemas, or static files.
3. Ensure no human-centric files (README.md, INSTALLATION.md) are created.

## Step 3: Draft Core Logic (SKILL.md)
1. Use the template in `assets/skill-template.md` as the starting point.
2. Write all instructions in the **third-person imperative** (e.g., "Extract the text," "Run the build").
3. **Enforce Progressive Disclosure:**
* Keep the main logic under 500 lines.
* If a procedure requires a large schema or complex rule set, move it to `references/`.
* Command the agent to read the specific file only when needed: *"Read references/api-spec.md to identify the correct endpoint."*

## Step 4: Identify and Bundle Scripts
1. Identify "fragile" tasks (regex, complex parsing, or repetitive boilerplate).
2. Outline a single-purpose script for the `scripts/` directory.
3. Ensure the script uses standard output (stdout/stderr) to communicate success or failure to the agent.

## Step 5: Final Logic Validation
1. Review the `SKILL.md` for "hallucination gaps" (points where the agent is forced to guess).
2. Verify all file paths are **relative** and use forward slashes (`/`).
3. Cross-reference the final output against `references/checklist.md`.

## Error Handling
* **Metadata Failure:** If `scripts/validate-metadata.py` fails, identify the specific error (e.g., "STYLE ERROR") and rewrite the field to remove first/second person pronouns.
* **Context Bloat:** If the draft exceeds 500 lines, extract the largest procedural block and move it to a file in `references/`.
21 changes: 21 additions & 0 deletions .claude/skills/skill-creator/assets/SKILL.template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
name: [skill-name]
description: [Action-oriented capability description in the third person. Max 1,024 characters. Include positive triggers. Do not use for [explicit negative triggers].]
---

# [Skill Title]

## Procedures

**Step 1: [Action Phase]**
1. [Third-person imperative instruction, e.g., "Extract the query parameters..."]
2. [Instruction referencing an asset, e.g., "Read `assets/template.json` to structure the final output."]

**Step 2: [Action Phase]**
1. [Decision tree/conditional logic, e.g., "If source maps are required, run `scripts/build.sh`. Otherwise, skip to Step 3."]
2. [Instruction requiring JiT loading, e.g., "Read `references/auth-flow.md` to map the specific error codes."]
3. Execute `python scripts/[script-name].py` to [perform deterministic action].

## Error Handling
* If `scripts/[script-name].py` fails due to [specific edge case], execute [recovery step].
* If [condition B occurs], read `references/[troubleshooting-file].md`.
32 changes: 32 additions & 0 deletions .claude/skills/skill-creator/references/checklist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Agent Skill Validation Checklist

Use this checklist to perform a final audit of the generated skill before deployment. Every item must be marked as "Pass" to ensure the skill is discoverable, lean, and deterministic.

## 1. Metadata & Discovery
* [ ] **Naming:** The `name` field is 1-64 characters, lowercase, and contains only numbers or single hyphens.
* [ ] **Directory Match:** The `name` field exactly matches the parent directory name.
* [ ] **Description Length:** The description is under 1,024 characters.
* [ ] **Trigger Optimization:** The description includes both use cases ("Use when...") and negative triggers ("Don't use for...").
* [ ] **Third-Person Tone:** The description avoids "I", "me", "my", "you", or "your".

## 2. File Structure & Paths
* [ ] **Flat Hierarchy:** All files in `scripts/`, `references/`, and `assets/` are exactly one level deep (no nested subfolders).
* [ ] **Standard Folders:** Only use `scripts/`, `references/`, and `assets/`.
* [ ] **No Human Docs:** The directory contains NO `README.md`, `CHANGELOG.md`, or `INSTALLATION_GUIDE.md`.
* [ ] **Forward Slashes:** All file paths in `SKILL.md` use forward slashes (`/`) regardless of the operating system.

## 3. Logic & Instructions (SKILL.md)
* [ ] **Lean Context:** The `SKILL.md` file is under 500 lines.
* [ ] **Imperative Mood:** Instructions use direct commands (e.g., "Extract," "Run," "Validate").
* [ ] **Deterministic Steps:** The workflow is a numbered, chronological sequence with clear decision trees.
* [ ] **Progressive Disclosure:** Large schemas, templates, or rule sets are stored in `references/` or `assets/` and read only when needed.
* [ ] **Specific Terminology:** Uses domain-native terms consistently (e.g., "component" instead of "file").

## 4. Scripts & Determinism
* [ ] **CLI Design:** Scripts in `scripts/` are designed as tiny CLIs that take arguments.
* [ ] **Feedback Loop:** Scripts provide descriptive `stdout` for success and `stderr` for failure to allow agent self-correction.
* [ ] **No Library Code:** Scripts are single-purpose; complex logic is offloaded to the repository's standard CLI or external tools.

## 5. Error Handling
* [ ] **Edge Cases:** The `SKILL.md` includes an "Error Handling" section addressing common failure states or missing configurations.
* [ ] **Validation:** The `SKILL.md` includes a step to run validation scripts where applicable.
50 changes: 50 additions & 0 deletions .claude/skills/skill-creator/scripts/validate-metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import re
import sys
import argparse

def validate_metadata(name, description):
errors = []

# 1. Validate Name Length
if not (1 <= len(name) <= 64):
errors.append(f"NAME ERROR: '{name}' is {len(name)} characters. Must be between 1-64.")

# 2. Validate Name Characters (lowercase, numbers, single hyphens)
# Regex: Starts/ends with alphanumeric, allows single hyphens in between
if not re.match(r"^[a-z0-9]+(-[a-z0-9]+)*$", name):
errors.append(
f"NAME ERROR: '{name}' contains invalid characters. "
"Use only lowercase letters, numbers, and single hyphens. "
"No consecutive hyphens, and cannot start/end with a hyphen."
)

# 3. Validate Description Length
if len(description) > 1024:
errors.append(
f"DESCRIPTION ERROR: Description is {len(description)} characters. "
"Must be 1,024 characters or fewer."
)

# 4. Check for Third-Person Perspective (Basic Heuristic)
first_person_words = {"i", "me", "my", "we", "our", "you", "your"}
desc_words = set(re.findall(r'\b\w+\b', description.lower()))
found_forbidden = first_person_words.intersection(desc_words)
if found_forbidden:
errors.append(
f"STYLE WARNING: Description contains first/second person terms: {found_forbidden}. "
"Use third-person imperative (e.g., 'Creates...', 'Updates...')."
)

if errors:
print("\n".join(errors), file=sys.stderr)
sys.exit(1)
else:
print("SUCCESS: Metadata is valid and optimized for discovery.")
sys.exit(0)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Validate skill metadata name and description")
parser.add_argument("--name", required=True, help="Skill name (lowercase, hyphen-separated)")
parser.add_argument("--description", default="", help="Skill description")
args = parser.parse_args()
validate_metadata(args.name, args.description)
37 changes: 34 additions & 3 deletions forge/rules/func-specs.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,37 @@ paths:

When writing or editing a `***functional specs***` section in a `.plain` file, always follow these rules:

## Voice
- Write each functional spec as a **statement of fact** — present tense, indicative mood — describing what the software *is* or *does* once built, not as a command telling a developer what to build
- **Name a concrete subject**: an actor (`A :User: can …`), a named component or concept (`:PdfRenderer: lays out …`, `:Order: processing depends on …`), or the affected data in passive voice (`All :Resource: items are returned`)
- **Avoid the vague subject "The system …"** — it says nothing about *which* part does the work. Prefer the concrete component/concept, or passive voice with the affected concept as the subject
- **Never open a spec with an imperative** like "Implement …", "Add …", "Create …", "Show …", "Display …", "Build …" — those read as instructions, not specifications
- Do **not** use "should" / "should be able to" in a functional spec — that is requirement-modal voice; state the fact directly

BAD — imperative commands, or the vague "The system":

```plain
***functional specs***

- Implement the entry point for :App:.

- The system shows :TaskList:.

- Add :Task:.
```

GOOD — statements of fact with concrete subjects:

```plain
***functional specs***

- :App: has an entry point.

- The :TaskList: is displayed.

- A :User: can add a :Task:. Only valid :Task: items are added.
```

## Complexity limit
- Each functional spec must imply a **maximum of 200 changed lines of code**
- If a spec is too large, use `break-down-func-spec` to split it into multiple smaller, independent specs
Expand Down Expand Up @@ -65,11 +96,11 @@ When writing or editing a `***functional specs***` section in a `.plain` file, a
```plain
***functional specs***

- Implement the entry point for :App:.
- :App: has an entry point.

- :User: should be able to add :Task:. Only valid :Task: items can be added.
- A :User: can add a :Task:. Only valid :Task: items are added.

- :User: should be able to send a :Message: to a :Conversation:.
- A :User: can send a :Message: to a :Conversation:.
- A :Message: must have non-empty content.
- The :Message: is appended to the end of the :Conversation:.
- All :Participant: members of the :Conversation: can see the new :Message:.
Expand Down
17 changes: 14 additions & 3 deletions forge/rules/line-length.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,36 @@ These rules apply to **every** section — `***definitions***`, `***implementati
BAD — line is too long:

```plain
- :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle(), which returns a list of :EventEnvelope: dicts conforming to the gateway's contract.
***functional specs***

- :GatewayWebhook: hands off :StripeRequest: to :StripeIntegration:.handle(), which returns a list of :EventEnvelope: dicts conforming to the gateway's contract.
```

WRONG SYNTAX (AVOID AT ALL COSTS) — bare indented continuation without a leading `- `:

```plain
- :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle(),
***functional specs***

- :GatewayWebhook: hands off :StripeRequest: to :StripeIntegration:.handle(),
which returns a list of :EventEnvelope: dicts conforming to the gateway's
contract.
```

GOOD — split at a natural clause boundary into nested `- ` bullets:

```plain
- :GatewayWebhook: should hand off :StripeRequest: to :StripeIntegration:.handle()
***functional specs***

- :GatewayWebhook: hands off :StripeRequest: to :StripeIntegration:.handle()
- The method returns a list of :EventEnvelope: dicts.
- The dicts must conform to the gateway's :EventEnvelope: contract.
```

## What never goes inline
- Long URLs, schema fragments, or example payloads — those belong in `resources/` per [`linked-resources.md`](linked-resources.md)
- If you find yourself pasting a multi-line block into a spec line, stop and link the file instead

## Presenting `.plain` examples
- Show every example snippet under its owning section header — e.g. `***functional specs***`, `***definitions***` — so the reader can see which section the lines belong in
- Separate top-level `- ` items with a single blank line; keep nested `- ` clarifications directly under their parent with **no** blank line between parent and child
- These conventions apply to canonical / "good" / "after" / "acceptable" example blocks; BAD / WRONG / `Before:` / `Too complex:` blocks show the header too but may otherwise deviate (that is the point of showing them)
13 changes: 7 additions & 6 deletions forge/rules/linked-resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ A linked resource **must not** be any of the following:
- Litmus test: "Would the renderer benefit from reading the bytes at this URL / folder?" If yes, save it to a file and link the file. If no (it's a runtime value the code carries forward), it can stay as plain text

## Structured protocol artifacts must be linked, never transcribed
- JSON Schema, OpenAPI / Swagger, GraphQL SDL, Protobuf `.proto`, Avro / Thrift schemas, XML XSDs, AsyncAPI specs, JSON-RPC method definitions, wire-protocol descriptions, payload examples — anything with a formal machine-readable shape — belongs in a file under `resources/` (or a subfolder of the `.plain` file's directory)
- JSON Schema, OpenAPI / Swagger, GraphQL SDL, Protobuf `.proto`, Avro / Thrift schemas, XML XSDs, AsyncAPI specs, JSON-RPC method definitions, wire-protocol descriptions, payload examples — anything with a formal machine-readable shape — belongs in a file under `resources/` (or another directory within the project)
- The spec line should describe the *role* of the artifact ("the request body conforms to ...", "the public API surface is defined in ...") rather than its contents
- Reasons: one source of truth (no drift between prose and schema); the renderer and the generated code can both consume the file directly; schema changes show up cleanly as diffs

Expand All @@ -39,7 +39,7 @@ A linked resource **must not** be any of the following:

***functional specs***

- :User: should be able to add :Task: by POSTing :TaskCreateRequest: to the `POST /tasks` endpoint of :TasksAPI:.
- A :User: can add a :Task: by POSTing :TaskCreateRequest: to the `POST /tasks` endpoint of :TasksAPI:.
- The endpoint responds per :TasksAPI:.
```

Expand All @@ -56,11 +56,12 @@ A linked resource **must not** be any of the following:

***functional specs***

- :User: should be able to add :Task: using :TaskModalSpec:.
- A :User: can add a :Task: using :TaskModalSpec:.

- :User: should be able to edit :Task: using :TaskModalSpec:.
- A :User: can edit a :Task: using :TaskModalSpec:.
```

## File location and path resolution
- Paths are resolved relative to the `.plain` file's directory
- The conventional location is `resources/` under the `.plain` file's directory
- Paths are resolved relative to the directory where `codeplain` is run (the current working directory)
- Relative paths may traverse into parent directories — `[resource](../../resources/resource.md)` is valid — as long as they resolve to a real text file on disk
- The conventional location is a `resources/` directory; keep the resource inside the project so the path stays stable from wherever `codeplain` is run
8 changes: 4 additions & 4 deletions forge/skills/add-acceptance-test/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ Acceptance tests are nested under the functional spec they verify, using a `***a
```plain
***functional specs***

- The system should process :Task: items in batches of 100.
- :Task: items are processed in batches of 100.

***acceptance tests***
- Processing 250 :Task: items should result in 3 batches.

- Each batch should contain at most 100 items.
```

Expand All @@ -55,8 +56,7 @@ BAD — bare continuation lines (invalid ***plain syntax, will not render):

```plain
***acceptance tests***
- Processing 250 :Task: items should result in 3 batches with the
last batch containing the remaining 50 items.
- Processing 250 :Task: items should result in 3 batches with the last batch containing the remaining 50 items.
```

GOOD — every line starts with `- `:
Expand All @@ -76,7 +76,7 @@ An acceptance test is essentially an **example that illustrates** the functional

```
Functional spec:
- The system should return :Resource: items sorted by creation date in descending order.
- :Resource: items are returned sorted by creation date in descending order.

Good (consistent):
- The first :Resource: in the response should have the most recent creation date.
Expand Down
7 changes: 7 additions & 0 deletions forge/skills/add-concept/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,15 @@ A concept definition is a bullet in `***definitions***` that starts with the con

```plain
***definitions***

- :ConceptName: is a description of what it represents.
```

Attributes and constraints are nested sub-bullets:

```plain
***definitions***

- :Task: describes an activity that needs to be done by :User:. :Task: has:
- Name - a short description (required)
- Notes - additional details (optional)
Expand All @@ -66,6 +69,8 @@ Attributes and constraints are nested sub-bullets:
BAD — bare continuation lines (invalid ***plain syntax, will not render):

```plain
***definitions***

- :Task: describes an activity that needs to be done by :User:.
- Name is a short description that the user provides when creating
the task and is shown in the task list.
Expand All @@ -74,6 +79,8 @@ BAD — bare continuation lines (invalid ***plain syntax, will not render):
GOOD — every line starts with `- `:

```plain
***definitions***

- :Task: describes an activity that needs to be done by :User:.
- Name is a short description provided when creating the task.
- The name is shown in the task list.
Expand Down
Loading