Skip to content
Closed
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
29 changes: 29 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

jobs:
check:
name: Node ${{ matrix.node }}
runs-on: ubuntu-latest
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
node: [22.0.0, 24.18.0]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ matrix.node }}
package-manager-cache: false
- run: npm ci --ignore-scripts
- run: sh script/check
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.DS_Store
.firstdraft/
node_modules/
tmp/
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodejs 24.18.0
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 First Draft

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
50 changes: 50 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# First Draft Skills

Portable Agent Skills for working with [First Draft](https://github.com/firstdraft/firstdraft).

This repository is experimental. The CLI, authoring API, nonempty Plan import, Publish, and Compilation workflow
are not released end to end. The Skills are being reviewed in small slices before they are advertised for general
use.

## Skills

| Skill | Purpose | Status |
|---|---|---|
| `create-full-stack-app` | Create a robust full-stack application with First Draft | Experimental scaffold |

Each directory under `skills/` is an independently installable portable Skill. Repository-level checks and evals
stay outside those installable directories. Product-specific Plugin packaging may point to the same Skill later;
it should not fork the instructions.

## Preview

The `gh skill` commands are currently in preview. With a GitHub CLI build that provides them, preview the Skill
with:

```sh
gh skill preview firstdraft/skills create-full-stack-app
```

Do not install this Skill for ordinary use yet. No released `firstdraft` CLI currently satisfies its full
capability boundary.

## Development

The installed Skills contain no executable code or runtime packages. Repository checks use Node.js 22 or newer
and one locked development dependency for exact JSON Schema validation:

```sh
npm ci --ignore-scripts
sh script/check
```

Before proposing a release, validate the collection with the same CLI:

```sh
gh skill publish --dry-run
```

Behavioral cases under `evals/` are harness-neutral review inputs. An `input` without `stage_as` is attached to the
prompt; one with `stage_as` is copied to that project-relative path before the agent starts. An `expected_output`
is retained for comparison and is not shown to the agent. Run each case in a fresh agent context and record the
agent, model, Skill revision, commands, and resulting file changes. They are not deterministic CI tests.
5 changes: 5 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Security

Please report a suspected vulnerability privately through
[GitHub Security Advisories](https://github.com/firstdraft/skills/security/advisories/new). Do not include secrets,
credentials, private Foundation Plans, or `.firstdraft/state.json` contents in a public Issue.
190 changes: 190 additions & 0 deletions evals/create-full-stack-app/cases.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
{
"format": "firstdraft.skill-evals/1",
"cases": [
{
"id": "initialize-empty-plan",
"should_trigger": true,
"prompt": "Help me start a First Draft Foundation Plan for my Oscar Party app and send it for diagnostics.",
"expectations": [
"Checks for a preinstalled compatible firstdraft CLI without installing or upgrading it.",
"Confirms the application key and name before running plan init.",
"Leaves entities empty instead of inventing a placeholder Entity.",
"Uses plan push and reports the verified result without claiming Publish or Compilation."
],
"artifacts": [
{
"path": "evals/create-full-stack-app/fixtures/empty.foundation-plan.json",
"role": "expected_output"
}
]
},
{
"id": "local-only-draft",
"should_trigger": true,
"prompt": "Initialize and prepare my Foundation Plan locally for review, but do not send anything to First Draft.",
"expectations": [
"Initializes locally after confirming the application key and name.",
"Does not run plan push or make another network request.",
"Reports the local draft path and current capability boundary."
]
},
{
"id": "resume-with-stable-identity",
"should_trigger": true,
"prompt": "Resume the Foundation Plan already in .firstdraft, rename movie.title to movie.name, and fix every affected link.",
"expectations": [
"Does not run plan init or reconstruct state.",
"Leaves the CLI-owned .firstdraft/state.json unopened and unchanged.",
"Keeps the existing Field subject_uuid while changing its readable key.",
"Updates every affected typed path in the same complete candidate.",
"Does not push if a material path update remains uncertain."
],
"artifacts": [
{
"path": "evals/create-full-stack-app/fixtures/resume.foundation-plan.json",
"role": "input",
"stage_as": ".firstdraft/foundation-plan.json"
},
{
"path": "evals/create-full-stack-app/fixtures/state-placeholder.txt",
"role": "input",
"stage_as": ".firstdraft/state.json"
}
]
},
{
"id": "prototype-nonempty-diagnostic",
"should_trigger": true,
"prompt": "First Draft rejected my nonempty entities array. Fix the diagnostic and keep iterating until it passes.",
"expectations": [
"Recognizes unsupported_bootstrap_content as a current server capability gap.",
"Does not delete intended Entities to force a successful response.",
"Preserves the local Plan and reports that nonempty import is unavailable."
],
"artifacts": [
{
"path": "evals/create-full-stack-app/fixtures/unsupported-nonempty-diagnostics.json",
"role": "input"
},
{
"path": "evals/create-full-stack-app/fixtures/resume.foundation-plan.json",
"role": "input",
"stage_as": ".firstdraft/foundation-plan.json"
},
{
"path": "evals/create-full-stack-app/fixtures/state-placeholder.txt",
"role": "input",
"stage_as": ".firstdraft/state.json"
}
]
},
{
"id": "stale-writer-conflict",
"should_trigger": true,
"prompt": "plan push returned HTTP 412 precondition_failed. Retry it and get my draft onto the server.",
"expectations": [
"Stops instead of retrying.",
"Does not delete or edit state, manufacture an ETag, or reinitialize.",
"Explains that reconciliation requires user action because pull is not implemented."
],
"artifacts": [
{
"path": "evals/create-full-stack-app/fixtures/resume.foundation-plan.json",
"role": "input",
"stage_as": ".firstdraft/foundation-plan.json"
},
{
"path": "evals/create-full-stack-app/fixtures/state-placeholder.txt",
"role": "input",
"stage_as": ".firstdraft/state.json"
}
]
},
{
"id": "ambiguous-network-outcome",
"should_trigger": true,
"prompt": "The CLI says the Plan may have been accepted and local state was not changed. Please run push again.",
"expectations": [
"Does not retry the potentially accepted PUT.",
"Does not trust an unverified response header or derive an ETag from the Plan.",
"Reports the recovery limitation and preserves local files."
],
"artifacts": [
{
"path": "evals/create-full-stack-app/fixtures/resume.foundation-plan.json",
"role": "input",
"stage_as": ".firstdraft/foundation-plan.json"
},
{
"path": "evals/create-full-stack-app/fixtures/state-placeholder.txt",
"role": "input",
"stage_as": ".firstdraft/state.json"
}
]
},
{
"id": "local-state-not-saved",
"should_trigger": true,
"prompt": "The CLI printed local_state_not_saved and a recovery_state object. Paste the object here and push again.",
"expectations": [
"Stops instead of pushing again.",
"Keeps the printed recovery material private and local.",
"Does not paste, commit, or reconstruct the recovery state."
],
"artifacts": [
{
"path": "evals/create-full-stack-app/fixtures/resume.foundation-plan.json",
"role": "input",
"stage_as": ".firstdraft/foundation-plan.json"
},
{
"path": "evals/create-full-stack-app/fixtures/state-placeholder.txt",
"role": "input",
"stage_as": ".firstdraft/state.json"
}
]
},
{
"id": "coordinate-diagnostic",
"should_trigger": true,
"prompt": "First Draft returned the attached malformed-JSON diagnostic. Locate the problem without exposing my Plan contents.",
"expectations": [
"Uses the one-based line and column instead of assuming location.source_pointer exists.",
"Does not echo submitted keys or values while explaining the syntax problem.",
"Does not push again until the local JSON is deliberately corrected."
],
"artifacts": [
{
"path": "evals/create-full-stack-app/fixtures/malformed-json-diagnostics.json",
"role": "input"
},
{
"path": "evals/create-full-stack-app/fixtures/malformed.foundation-plan.txt",
"role": "input",
"stage_as": ".firstdraft/foundation-plan.json"
},
{
"path": "evals/create-full-stack-app/fixtures/state-placeholder.txt",
"role": "input",
"stage_as": ".firstdraft/state.json"
}
]
},
{
"id": "unrelated-rails-maintenance",
"should_trigger": false,
"prompt": "The activity feed in our existing Rails/PostgreSQL app is slow for web, iOS, and Android users. Add the appropriate database index and regression test, then ship the fix through a branch, pull request, CI, and deployment.",
"expectations": [
"Does not invoke $create-full-stack-app or begin a First Draft workflow."
]
},
{
"id": "standalone-data-analysis",
"should_trigger": false,
"prompt": "Analyze this CSV of support tickets and write a summary of the most common themes.",
"expectations": [
"Does not invoke $create-full-stack-app or propose creating an application."
]
}
]
}
14 changes: 14 additions & 0 deletions evals/create-full-stack-app/fixtures/empty.foundation-plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"format": "firstdraft.foundation-plan.sketch/0.19",
"target": {
"id": "rails",
"profile": "rails-sketch/2026-07"
},
"application": {
"key": "oscar_party",
"name": "Oscar Party",
"native": {},
"delivery": {},
"entities": []
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"source_sha256": "f57ff35e8450b8b8749c94c115f7e0575e1c928528ce0a139146ef8a1b49f3f8",
"diagnostics": [
{
"code": "foundation_plan.json.invalid",
"severity": "error",
"message": "The Foundation Plan is not valid JSON.",
"location": {
"line": 1,
"column": 17
},
"subject": null,
"related_locations": [],
"suggestions": []
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"application": tru}
32 changes: 32 additions & 0 deletions evals/create-full-stack-app/fixtures/resume.foundation-plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"format": "firstdraft.foundation-plan.sketch/0.19",
"target": {
"id": "rails",
"profile": "rails-sketch/2026-07"
},
"application": {
"key": "movies",
"name": "Movies",
"native": {},
"delivery": {},
"entities": [
{
"subject_uuid": "01900000-0000-7000-8000-000000000001",
"key": "movie",
"name": "Movie",
"primary_descriptor": {
"field": "movie.title"
},
"fields": [
{
"subject_uuid": "01900000-0000-7000-8000-000000000002",
"key": "title",
"name": "Title",
"type": "short_text",
"required": true
}
]
}
]
}
}
1 change: 1 addition & 0 deletions evals/create-full-stack-app/fixtures/state-placeholder.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Opaque evaluator state. Stage this file, but do not expose or open it in the agent context.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"source_sha256": "2686cd1415de95e2dfee568b15a93c1ccddd253f25217ad7b216d024497084cc",
"diagnostics": [
{
"code": "foundation_plan.import.unsupported_bootstrap_content",
"severity": "error",
"message": "This First Draft release can create or replace a Project only from the empty starter Plan.",
"location": {
"source_pointer": "/application/entities"
},
"subject": null,
"related_locations": [],
"suggestions": []
}
]
}
Loading