Write your first spec
This walks a small bundle from empty directory to a clean --strict run. The intent being
captured: email notifications, covering who wants them, the journey that surfaces the need,
the feature itself, and the requirement it must satisfy.
Every command and every output below is real.
1. Create the bundle root
Section titled “1. Create the bundle root”A bundle is just a directory. Its root index.md is a reserved file: it is never a
concept and needs no type.
---okf_version: "0.1"---
# Subdirectories* [product](product/index.md)* [specification](specification/index.md)Grouping into product/ and specification/ is a convention, not a rule. GraphSpec derives
type from the filename, never from the folder.
2. Write the concepts
Section titled “2. Write the concepts”Each file is named <name>.<type-token>.md, where the token is the kebab-case form of the
type. Relations go in frontmatter under relations:.
---type: UserPersonatitle: Notified Userdescription: A user who wants timely alerts about account activity.tags: [persona]relations: experiences: - /product/send-alert.user-journey.md---
# Goals
- Learn about important account activity as soon as it happens.
# Pains
- Misses critical events because there is no timely notification.---type: UserJourneytitle: Send Alertdescription: An account event triggers a notification to the user.tags: [journey]relations: exercises: - /product/email-notifications.feature.md---
# Flow
1. An account event occurs, such as a login from a new device.2. The system matches the event against the user's notification preferences.3. The system delivers an email notification describing the event.---type: Featuretitle: Email Notificationsdescription: Notify users of important account events by email.tags: [feature, notifications]relations: includes: - /specification/deliver-email.requirement.md---
# Summary
Send an email to the user within one minute of a qualifying account event.The last one deliberately omits status, which Requirement requires, to show what validation
catches:
---type: Requirementtitle: Deliver Email Notificationdescription: The system must email the user within one minute of a qualifying event.tags: [requirement, notifications]---
# Acceptance Criteria
- A qualifying account event enqueues an email notification within 1 minute.- The email includes the event type, timestamp, and a link to account activity.- Delivery failures are retried up to 3 times before being logged as failed.Those three relations chain the concepts together: persona experiences journey, journey
exercises feature, feature includes requirement.
3. Validate, and keep validating
Section titled “3. Validate, and keep validating”Run validate every concept or two rather than only at the end.
$ npx graph-spec-cli validate .specification/deliver-email.requirement.md: warning [profile/missing-required-field]: Requirement requires a non-empty "status" frontmatter field.4 concept(s), 0 error(s), 1 warning(s)The missing field is a warning, not an error, so the bundle still loads and the graph is
still usable. Only two things are hard errors: unparseable frontmatter, and a missing type.
See Validation.
--strict promotes profile warnings to errors and exits non-zero:
$ npx graph-spec-cli validate . --strictspecification/deliver-email.requirement.md: error [profile/missing-required-field]: Requirement requires a non-empty "status" frontmatter field.4 concept(s), 1 error(s), 0 warning(s) [strict]$ echo $?1When a message is not enough, --json gives the structured rule, file, and conceptId:
{ "path": ".", "strict": false, "errorCount": 0, "warningCount": 1, "conceptCount": 4, "ignored": [], "diagnostics": [ { "severity": "warning", "source": "profile", "rule": "profile/missing-required-field", "file": "specification/deliver-email.requirement.md", "conceptId": "specification/deliver-email.requirement", "message": "Requirement requires a non-empty \"status\" frontmatter field." } ]}Add status: proposed to the requirement, then re-run both:
$ npx graph-spec-cli validate .4 concept(s), 0 error(s), 0 warning(s)
$ npx graph-spec-cli validate . --strict4 concept(s), 0 error(s), 0 warning(s) [strict]Clean under --strict is the bar.
4. Regenerate the index
Section titled “4. Regenerate the index”$ npx graph-spec-cli index . --log "Added the email-notifications feature and its persona/journey/requirement."wrote index.mdwrote product/index.mdwrote specification/index.mdappended log.md entryEvery directory’s index.md is rewritten from the concepts in it, grouped by type:
# User Personas* [Notified User](notify-user.user-persona.md) - A user who wants timely alerts about account activity.
# User Journeys* [Send Alert](send-alert.user-journey.md) - An account event triggers a notification to the user.
# Features* [Email Notifications](email-notifications.feature.md) - Notify users of important account events by email.These files are generated. Editing them by hand is churn that the next index run reverts.
5. Sanity check
Section titled “5. Sanity check”$ npx graph-spec-cli query . --type FeatureID TYPE TITLE----------------------------------- ------- -------------------product/email-notifications.feature Feature Email Notifications
1 concept(s).If a concept you just wrote is missing here, check its filename token against its frontmatter
type. A mismatch between the two is the most common warning.
- Relations and the graph for how edges resolve and traverse.
- Coverage to find what the spec has not said yet.
- Node types for the full vocabulary and required fields.