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
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ Thumbs.db
npm-debug.log*

# Template forks: build.js writes to docs/ by default.
# Uncomment the line below if you want to keep generated output out of git
# and deploy via the bundled workflow instead.
# Option A (recommended): Uncomment docs/ below. The bundled GitHub Actions
# workflow builds and deploys automatically — no need to commit generated output.
# Option B: Commit docs/ so GitHub Pages can serve it without a workflow.
# This repo uses Option B for its /demo/ output; template forks should use Option A.
# docs/

# Environment
Expand Down
11 changes: 6 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ Every entity file starts with YAML frontmatter between `---` delimiters. See exi
**Primary entities:**
```yaml
---
title: Data Encryption
id: data-encryption
name: Data Encryption
group: technical
last_verified: 2025-01-15
---
Expand All @@ -32,7 +33,7 @@ last_verified: 2025-01-15
**Container entities:**
```yaml
---
title: ISO 27001
name: ISO 27001
status: active
authority: iso
last_verified: 2025-01-15
Expand All @@ -42,8 +43,8 @@ last_verified: 2025-01-15
**Authority entities:**
```yaml
---
title: International Organization for Standardization
type: standards-body
id: iso
name: International Organization for Standardization
last_verified: 2025-01-15
---
```
Expand Down Expand Up @@ -132,7 +133,7 @@ Container entity files have a specific structure with a timeline table and provi

```markdown
---
title: Example Framework
name: Example Framework
status: active
authority: org-id
---
Expand Down
96 changes: 84 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ A template for building structured, version-controlled knowledge bases with an o

**[Knowledge as Code](https://knowledge-as-code.com)** is a pattern created for [PAICE.work](https://paice.work/) PBC. It applies software engineering practices to knowledge management: plain text, Git-native, zero-dependency, ontology-driven, multi-output from a single source.

## Live Examples
## What it produces

**[Live demo →](https://knowledge-as-code.com/demo/)** — the output of this template's example data, deployed on GitHub Pages. Includes a searchable HTML site, coverage matrix, timeline, comparison tool, and JSON API.

Built examples using this template:

- [AI Tool Watch](https://aitool.watch) — AI model capabilities across 12 products
- [Every AI Law](https://everyailaw.com) — global AI regulatory landscape
- [Meeting Standards Reference](https://meetings.snapsynapse.com) — meeting facilitation standards

## Quick Start

1. **Use this template** -- click "Use this template" on GitHub, or clone locally
2. **Edit `project.yml`** -- define your domain entities, groups, colors, and site identity
3. **Replace example data** -- see [Replacing example data](#replacing-example-data) below
4. **Build** -- `node scripts/build.js` (or `npm run build`)
5. **Deploy** -- push to GitHub, Pages deploys automatically
1. **Use this template** -- on GitHub, click the green "Use this template" button (not "Clone"). This creates a new repo with no git history and no upstream connection. Cloning is fine for local exploration but won't give you a clean starting repo.
2. **Edit `project.yml`** -- start with the entity names (`entities.primary.name`, `entities.container.name`, etc.) and groups. You can adjust colors and navigation later. Leave `url` until your GitHub repo is configured.
3. **Replace example data** -- delete the files in `data/examples/requirements/`, `data/examples/frameworks/`, `data/examples/organizations/`, and `data/examples/mapping/index.yml`, then add your own. See [Replacing example data](#replacing-example-data) and [`data/_schema.md`](data/_schema.md) for the format.
4. **Build** -- `node scripts/build.js`. A successful build prints `Build complete — N HTML pages, N JSON API files`. Check the `docs/` directory for the output, and open any HTML file in a browser to verify it looks right.
5. **Deploy** -- push to GitHub. The included workflow deploys to GitHub Pages automatically.

## What You Get

Expand Down Expand Up @@ -63,6 +67,50 @@ Authority → Container → Provision → Primary

Primaries are stable; containers are unstable. When a framework is amended, its provisions change, but the underlying requirements persist.

### How the pieces connect

```
project.yml data/examples/
(names, colors, config) (one .md file per entity)
\ /
\ /
+----> scripts/build.js <----+ data/examples/mapping/index.yml
| (connects containers to primaries)
+------------+------------+
| | |
docs/ docs/ docs/api/v1/
(HTML site) llms.txt (JSON API)
(sitemap) agents.json context.jsonld
```

You edit `project.yml` and `data/`. The build script reads both and writes everything under `docs/`. You never edit `docs/` directly.

### gist semantic layer

By default, every built site includes a semantic layer backed by [gist](https://semanticarts.com/gist/) — a minimalist upper ontology for the enterprise by Semantic Arts. This adds:

- `@type` annotations on every item in the JSON API (e.g. `"@type": "gist:KnowledgeConcept"`)
- `api/v1/context.jsonld` — a JSON-LD context file mapping KaC terms to gist IRIs
- `ontology` block in `api/v1/index.json` with the framework name, base IRI, and attribution

The default role-to-class mapping:

| KaC role | gist class |
|----------|-----------|
| primary | `gist:KnowledgeConcept` |
| container | `gist:Specification` |
| authority | `gist:Organization` |
| secondary | `gist:Commitment` |

Override any mapping in `project.yml` under `ontology.entities.<role>.gist_class`. To disable entirely:

```yaml
ontology:
enabled: false
```

When enabled, CC BY 4.0 attribution to Semantic Arts is required on any published site. The attribution string is included automatically in `api/v1/index.json`.

## Configuration

All domain-specific settings live in `project.yml`:
Expand Down Expand Up @@ -94,6 +142,8 @@ The template ships with example data in `data/examples/` (ISO 27001, NIST CSF).

The build script looks for data in `data/examples/` first, then `data/`. You can rename `data/examples/` to `data/` if you prefer a flatter structure.

**What to keep:** Only `data/` contents and `project.yml` values need replacing. Do not delete `scripts/`, `.github/workflows/`, `mcp-server.js`, `mcp.json`, or `package.json` — these are the template engine and deployment config.

## Commands

```bash
Expand Down Expand Up @@ -143,16 +193,36 @@ The MCP server exposes your knowledge base as tools that AI agents can call. Too
node mcp-server.js
```

The server reads `project.yml` at startup and exposes tools for listing and retrieving each entity type. For example, with the default config you get tools like `list_requirements`, `get_requirement`, `list_frameworks`, `get_framework`, etc. The exact tool names depend on your entity configuration.
The server reads `project.yml` at startup and exposes tools for listing and retrieving each entity type. Tool names are derived from your entity config by lowercasing and replacing non-alphanumeric characters with hyphens:

| Config value | Tool name |
|-------------|-----------|
| `plural: Requirements` | `list_requirements` |
| `name: Requirement` | `get_requirement` |
| `plural: Frameworks` | `list_frameworks` |
| `name: Framework` | `get_framework` |
| `plural: Organizations` | `list_organizations` |
| `name: Organization` | `get_organization` |

Two fixed tools are always present regardless of config: `get_matrix` and `get_mappings`.

## Validation

`node scripts/validate.js` checks cross-references before building. Common errors and fixes:

| Error message | Cause | Fix |
|--------------|-------|-----|
| `Mapping "X" references unknown container "Y"` | `regulation` field in mapping doesn't match any container filename | Check the container file exists and the `regulation` value matches the filename (without `.md`) |
| `Mapping "X" references unknown primary "Y"` | `obligations` entry doesn't match any primary filename | Check the primary file exists and the ID matches |
| `Mapping "X" references unknown authority "Y"` | `authority` field doesn't match any authority filename | Check the authority file exists |
| `Container "X" references unknown authority "Y"` | `authority` frontmatter in container file doesn't match any authority | Create the authority file or correct the ID |
| `No data directory found` | Neither `data/examples/` nor `data/` exists | Check your data directory path and config |

## Verification

Knowledge as Code includes a verification scaffold for detecting stale data:
`node scripts/verify.js` detects stale entities and validates cross-reference completeness. A weekly GitHub Actions workflow runs it automatically and opens an issue on drift.

- Add `last_verified: YYYY-MM-DD` to entity frontmatter
- Run `node scripts/verify.js` to check for staleness
- Configure threshold in `project.yml` under `verification.staleness_days`
- See [VERIFICATION.md](VERIFICATION.md) for details on adding AI-assisted verification
See [VERIFICATION.md](VERIFICATION.md) for the full guide: staleness thresholds, CI integration, and AI-assisted content review.

## Ecosystem

Expand Down Expand Up @@ -180,6 +250,8 @@ Read the full pattern definition at [knowledge-as-code.com](https://knowledge-as

Knowledge as Code is a [PAICE.work](https://paice.work/) project. See [ATTRIBUTION.md](ATTRIBUTION.md) for details.

The default semantic layer uses [gist](https://semanticarts.com/gist/) by Semantic Arts, Inc., licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Required attribution: "Semantic Arts, Inc. gist ontology (CC BY 4.0) https://semanticarts.com/gist".

## Deploying

When you use this template, update the following:
Expand Down
22 changes: 4 additions & 18 deletions VERIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,16 @@ The script validates that:
- Every mapping references valid primary entity IDs
- Every mapping references valid container IDs

## Setting `last_verified` in Entity Frontmatter
## Setup

Add a `last_verified` field with an ISO date to any entity's frontmatter:

```yaml
---
title: Data Encryption
group: technical
last_verified: 2025-01-15
---
```

When you review an entity and confirm its content is current, update this date. The verification script will then consider it fresh until the staleness threshold is exceeded.

## Configuring the Staleness Threshold

In `project.yml`, set the number of days before an entity is considered stale:
Add `last_verified: YYYY-MM-DD` to any entity's frontmatter and set the staleness window in `project.yml`:

```yaml
verification:
staleness_days: 90
staleness_days: 90 # default; use 30 for fast-moving domains, 180 for stable reference data
```

The default is 90 days. Adjust this based on how frequently your domain changes. Fast-moving regulatory environments may warrant 30 days; stable reference data might use 180.
When you review an entity and confirm its content is current, update the date. Entities without `last_verified` are reported as "never verified."

## Running Verification

Expand Down
13 changes: 8 additions & 5 deletions data/_schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,16 +146,19 @@ The heading name should match your container entity's plural name (e.g., "Regula
The mapping file connects containers to primaries through secondary (provision) entities:

```yaml
- id: iso-27001-access-control # Unique provision ID
regulation: iso-27001 # Container file name (without .md)
authority: iso # Authority ID
source_heading: Information Security Controls (Annex A) # Must match an ## H2 in the container file
obligations: # List of primary entity IDs this provision maps to
- id: iso-27001-access-control # Required. Unique provision ID (kebab-case)
regulation: iso-27001 # Required. Container file name (without .md)
authority: iso # Required. Authority ID
source_heading: Information Security Controls (Annex A) # Required. Must match an ## H2 in the container file
source_file: data/examples/frameworks/iso-27001.md # Optional. Path to container file for tooling/traceability
obligations: # Required. List of primary entity IDs this provision maps to
- access-control
```

The `regulation` field should use your container entity name from config (the field name comes from `project.yml`). The `obligations` field should use your primary entity name from config.

`source_file` is informational — the build script resolves container files by `regulation` ID, not this path. It is useful for documentation tooling and traceability. If included, use the path relative to the repo root and match your configured `entities.container.directory`.

## File naming

- All files use kebab-case: `access-control.md`, `iso-27001.md`
Expand Down
8 changes: 4 additions & 4 deletions data/examples/mapping/index.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
- id: iso-27001-access-control
regulation: iso-27001
authority: iso
source_file: data/examples/container/iso-27001.md
source_file: data/examples/frameworks/iso-27001.md
source_heading: Information Security Controls (Annex A)
obligations:
- access-control

- id: iso-27001-data-quality
regulation: iso-27001
authority: iso
source_file: data/examples/container/iso-27001.md
source_file: data/examples/frameworks/iso-27001.md
source_heading: Data Quality Requirements (Clause 7.5)
obligations:
- data-quality

- id: nist-csf-incident-response
regulation: nist-csf
authority: nist
source_file: data/examples/container/nist-csf.md
source_file: data/examples/frameworks/nist-csf.md
source_heading: Incident Response (RS.AN, RS.MI)
obligations:
- incident-response

- id: nist-csf-access-control
regulation: nist-csf
authority: nist
source_file: data/examples/container/nist-csf.md
source_file: data/examples/frameworks/nist-csf.md
source_heading: Access Control (PR.AA)
obligations:
- access-control
2 changes: 1 addition & 1 deletion demo/agents.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"robots": "https://knowledge-as-code.com/demo/robots.txt"
},
"meta": {
"last_updated": "2026-04-09",
"last_updated": "2026-04-19",
"built_with": "Knowledge as Code",
"pattern_url": "https://knowledge-as-code.com",
"template_url": "https://github.com/snapsynapse/knowledge-as-code-template"
Expand Down
4 changes: 3 additions & 1 deletion demo/api/v1/authorities.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
{
"meta": {
"generated": "2026-04-09T23:00:18.276Z",
"generated": "2026-04-19T02:53:43.767Z",
"count": 2
},
"items": [
{
"@type": "gist:Organization",
"id": "iso",
"name": "International Organization for Standardization",
"jurisdiction": "International"
},
{
"@type": "gist:Organization",
"id": "nist",
"name": "National Institute of Standards and Technology",
"jurisdiction": "Federal"
Expand Down
2 changes: 1 addition & 1 deletion demo/api/v1/comparisons.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"meta": {
"generated": "2026-04-09T23:00:18.277Z"
"generated": "2026-04-19T02:53:43.767Z"
},
"comparisons": [
{
Expand Down
4 changes: 3 additions & 1 deletion demo/api/v1/containers.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
{
"meta": {
"generated": "2026-04-09T23:00:18.276Z",
"generated": "2026-04-19T02:53:43.766Z",
"count": 2
},
"items": [
{
"@type": "gist:Specification",
"id": "iso-27001",
"name": "ISO 27001",
"status": "active",
"effective": "2022-10-25",
"provision_count": 2
},
{
"@type": "gist:Specification",
"id": "nist-csf",
"name": "NIST Cybersecurity Framework",
"status": "active",
Expand Down
10 changes: 10 additions & 0 deletions demo/api/v1/context.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"@context": {
"gist": "https://ontologies.semanticarts.com/gist/",
"kac": "https://knowledge-as-code.com/demo/api/v1/",
"gist:KnowledgeConcept": "https://ontologies.semanticarts.com/gist/KnowledgeConcept",
"gist:Specification": "https://ontologies.semanticarts.com/gist/Specification",
"gist:Organization": "https://ontologies.semanticarts.com/gist/Organization",
"gist:Commitment": "https://ontologies.semanticarts.com/gist/Commitment"
}
}
10 changes: 8 additions & 2 deletions demo/api/v1/index.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
{
"meta": {
"generated": "2026-04-09T23:00:18.277Z",
"generated": "2026-04-19T02:53:43.767Z",
"version": "1.0",
"project": "example"
"project": "example",
"ontology": {
"framework": "gist",
"base_iri": "https://ontologies.semanticarts.com/gist/",
"context": "context.jsonld",
"attribution": "Semantic Arts, Inc. gist ontology (CC BY 4.0) https://semanticarts.com/gist"
}
},
"files": {
"primaries": {
Expand Down
Loading
Loading