From 9474d00b5532e1d10ee7b4f56397600cfb0eda3a Mon Sep 17 00:00:00 2001 From: Jay Flowers Date: Sun, 23 Aug 2026 19:29:32 -0400 Subject: [PATCH 1/7] docs: add blog-tutorials-batch openspec artifacts --- .../blog-tutorials-batch/.openspec.yaml | 2 + .../changes/blog-tutorials-batch/design.md | 69 +++++++++++ .../changes/blog-tutorials-batch/proposal.md | 93 ++++++++++++++ .../blog-tutorials-batch/specs/blog-posts.md | 117 ++++++++++++++++++ .../blog-tutorials-batch/specs/tutorials.md | 95 ++++++++++++++ .../changes/blog-tutorials-batch/tasks.md | 47 +++++++ 6 files changed, 423 insertions(+) create mode 100644 openspec/changes/blog-tutorials-batch/.openspec.yaml create mode 100644 openspec/changes/blog-tutorials-batch/design.md create mode 100644 openspec/changes/blog-tutorials-batch/proposal.md create mode 100644 openspec/changes/blog-tutorials-batch/specs/blog-posts.md create mode 100644 openspec/changes/blog-tutorials-batch/specs/tutorials.md create mode 100644 openspec/changes/blog-tutorials-batch/tasks.md diff --git a/openspec/changes/blog-tutorials-batch/.openspec.yaml b/openspec/changes/blog-tutorials-batch/.openspec.yaml new file mode 100644 index 0000000..711f289 --- /dev/null +++ b/openspec/changes/blog-tutorials-batch/.openspec.yaml @@ -0,0 +1,2 @@ +schema: unbound-force +created: 2026-08-23 diff --git a/openspec/changes/blog-tutorials-batch/design.md b/openspec/changes/blog-tutorials-batch/design.md new file mode 100644 index 0000000..f4dc1e0 --- /dev/null +++ b/openspec/changes/blog-tutorials-batch/design.md @@ -0,0 +1,69 @@ +## Context + +The website has 14 published blog posts in `content/blog/` and no tutorials section. There are 14 GitHub issues with detailed content outlines ready for implementation — 9 blog posts and 5 tutorials. The proposal (constitution alignment: all N/A — static content only) establishes the scope. + +The blog section uses standard Hugo/Doks Markdown with YAML frontmatter. Each post has a `weight` for ordering (lower = newer/higher position), `slug` for URL, `categories`, `tags`, and `contributors` fields. Weights currently range from 1 (section index) to 100. + +There is no tutorials section. Creating one requires a new content directory, section index, and navigation entry. + +## Goals / Non-Goals + +### Goals +- Produce 9 blog posts and 5 tutorials as standard Hugo Markdown files +- Create the tutorials section infrastructure (`_index.md`, navigation entry) +- Follow established blog frontmatter conventions exactly +- Source all content from the detailed outlines in the referenced GitHub issues +- Close all 14 issues upon merge + +### Non-Goals +- Custom layouts or shortcodes for tutorials — standard Doks Markdown rendering is sufficient +- Code samples that execute — all code blocks are illustrative/configuration examples +- Extensive cross-linking between blog posts and tutorials is deferred to a follow-up PR — each page stands alone in this batch. Natural pairings (e.g., blog #69 ↔ tutorial #70, blog #150 ↔ tutorial #151) SHOULD include a brief "Learn More" or "Try It" link to the companion page where one exists +- Images or diagrams — text-only content for this batch +- Restructuring existing blog posts or their weights + +## Decisions + +### D1: Tutorials live under `content/docs/tutorials/` + +Tutorials are documentation (step-by-step guides), not blog posts (opinion/analysis pieces). Placing them under `content/docs/` gives them sidebar navigation, table of contents, and the standard docs layout — all appropriate for instructional content. The Doks theme handles this automatically with no custom templates. + +### D2: Tutorial navigation at weight 37 + +The docs sidebar currently has: Getting Started (10), Projects (20), The Team (30), Reference (35), Changelog (38), Contributing (40). Tutorials fit between Reference and Changelog at weight 37, positioning them after reference material but before changelog and contributing — a natural reading order for someone learning the tools. + +### D3: Blog post weight allocation + +New blog posts will use weights 101-109 (ascending by issue number), placing them after all existing posts. The `_index.md` weight of 1 controls the section itself; individual post weights control ordering within the section. Higher weight = further down the list. Since blog posts are typically consumed newest-first and the blog page already sorts by date, weight is a secondary concern — but consistent allocation prevents future conflicts. + +### D4: Content sourcing from GitHub issues only + +Each issue contains a structured outline with sections, key points, and audience framing. Content will be written by expanding these outlines into full prose. During implementation, agents SHOULD use Dewey MCP tools (FA-003) or the Read tool (FA-004) to verify specific claims (version numbers, command names, configuration keys) against upstream repositories when practical. The issue outlines provide the structure and framing; upstream verification confirms accuracy of technical details. + +### D5: Slug naming convention + +Blog slugs follow the established pattern: lowercase, hyphenated, descriptive. Examples from existing posts: `gaze-in-practice`, `sandbox-isolation`, `convention-packs`. New posts will follow the same pattern. Tutorial URLs are determined by their directory/file path under `content/docs/tutorials/`. + +### D6: Frontmatter date + +All posts and tutorials in this batch will use the same date (2026-08-23) since they are being written as a batch. This is the implementation date, not the date of the feature being described. + +## Risks / Trade-offs + +### R1: Content accuracy without upstream verification + +**Risk**: Blog posts describe features from Gaze, Dewey, Pinkman, and Unbound Force. The GitHub issue outlines may reference implementation details that have since changed. + +**Mitigation**: The issues were filed by the team with accurate, detailed outlines. For this static content batch, the outlines are treated as authoritative. Any inaccuracies can be corrected in follow-up PRs after subject-matter review. + +### R2: Large PR size + +**Risk**: 16 new files in a single PR may be difficult to review. + +**Mitigation**: All files are independent Markdown with no cross-dependencies. Reviewers can evaluate each file individually. The files share no code or logic — a problem in one post does not affect others. + +### R3: Tutorial section may need refinement + +**Risk**: The tutorials section is new. Navigation placement (weight 37) and section description may need adjustment after seeing it in context. + +**Mitigation**: Both are trivially adjustable — weight is a single integer in TOML, and the section description is a line in `_index.md`. Visual verification during `npm run dev` will catch layout issues before merge. diff --git a/openspec/changes/blog-tutorials-batch/proposal.md b/openspec/changes/blog-tutorials-batch/proposal.md new file mode 100644 index 0000000..5d763bb --- /dev/null +++ b/openspec/changes/blog-tutorials-batch/proposal.md @@ -0,0 +1,93 @@ +## Why + +The website has 14 open GitHub issues for content that has been planned but not yet written — 9 blog posts and 5 tutorials. Each issue contains a detailed outline with section structure, key points, and target audience. The blog section currently has 14 published posts, but the tutorials section does not exist yet. Publishing this batch will: + +- Fill major content gaps in the website (tutorials section is entirely missing) +- Provide practical guides for Dewey, Gaze, Pinkman, and Unbound Force features +- Cover recent releases and capabilities (Dewey v3.1.0, Gaze baseline comparison, council-review-action, pluggable providers) +- Close 14 tracked issues in a single coordinated effort + +## What Changes + +### Blog Posts (9 new pages) + +Each blog post follows the established pattern in `content/blog/` with standard Hugo/Doks frontmatter. + +1. **CI failure classification** (#64) — How `/review-pr` separates pre-existing failures from PR-caused regressions +2. **AGENTS.md quality** (#65) — Why the quality of your AGENTS.md determines the quality of AI-generated code +3. **Dewey knowledge stores** (#69) — File-backed learnings that survive database deletion in Dewey v3.1.0 +4. **Dewey slash command UX** (#72) — How a markdown file became Dewey's best feature via `/dewey-store` +5. **Pluggable LLM providers** (#116) — Dewey's cloud-optional architecture with Ollama and Vertex AI support +6. **Gaze baseline comparison** (#150) — Per-function CRAP regression detection for CI gates +7. **Council review action** (#191) — Bringing the Divisor Council to GitHub Actions for AI code review in CI +8. **Prompt hardening** (#198) — Engineering agent prompts that survive Dynamic Context Protocol compression +9. **Multi-platform support** (#51) — How `uf init` scaffolds for both OpenCode and Cursor + +### Tutorials (5 new pages) + +Tutorials require creating a new `content/docs/tutorials/` section with its own `_index.md` and navigation entry. + +1. **Dewey knowledge stores setup** (#70) — From configuration to curated semantic search +2. **Dewey provider configuration** (#114) — Configuring embedding and synthesis providers (Ollama, Vertex AI) +3. **Gaze CRAP baseline in CI** (#151) — Setting up baseline comparison in GitHub Actions +4. **Pinkman OSS Scout** (#45) — Getting started with `/scout` discover/trend/audit/report modes +5. **Onboard customization** (#46) — Getting started with `/onboard` and the three interview phases + +### Infrastructure Changes + +- Create `content/docs/tutorials/_index.md` section index page +- Add tutorials navigation entry to `config/_default/menus/menus.en.toml` + +## Capabilities + +### New Capabilities +- `tutorials-section`: New documentation section for step-by-step guides, accessible from top-level navigation +- `blog-batch-content`: 9 new blog posts covering recent features across Gaze, Dewey, Unbound Force, and the Divisor Council + +### Modified Capabilities +- `site-navigation`: Updated to include tutorials section in the docs sidebar and potentially in the top-level menu + +### Removed Capabilities +- None + +## Impact + +- **Content files**: 15 new Markdown files (9 blog posts + 5 tutorials + 1 section index) +- **Navigation**: `config/_default/menus/menus.en.toml` updated for tutorials +- **No SCSS/layout changes**: All content uses standard Doks Markdown rendering +- **No dependency changes**: No new npm packages or Hugo modules +- **Issue tracking**: Closes GitHub issues #45, #46, #51, #64, #65, #69, #70, #72, #114, #116, #150, #151, #191, #198 + +## Constitution Alignment + +Assessed against the Unbound Force org constitution. + +### I. Autonomous Collaboration + +**Assessment**: N/A + +This change adds static website content (Markdown files). It does not modify any hero artifacts, agent communication protocols, or runtime coupling. Content is sourced from well-defined GitHub issue specifications. + +### II. Composability First + +**Assessment**: N/A + +Blog posts and tutorials are standalone Markdown pages. Each can be published, updated, or removed independently. The tutorials section is a standard Hugo content directory with no custom dependencies. + +### III. Observable Quality + +**Assessment**: N/A + +This change produces static HTML pages via Hugo's standard build pipeline. No machine-parseable output or provenance metadata is involved — these are human-readable articles. + +### IV. Testability + +**Assessment**: N/A + +Static content changes are validated by `npm run build` (Hugo compilation succeeds) and visual verification. No runtime components are introduced that would require isolation testing. + +### V. Security by Default + +**Assessment**: N/A + +This change adds static Markdown content files. No external inputs are processed, no dependencies are added, and no CI pipeline changes are made. Tutorial configuration examples MUST use placeholder values for secrets and MUST demonstrate SHA-pinned GitHub Actions where applicable. diff --git a/openspec/changes/blog-tutorials-batch/specs/blog-posts.md b/openspec/changes/blog-tutorials-batch/specs/blog-posts.md new file mode 100644 index 0000000..b667b31 --- /dev/null +++ b/openspec/changes/blog-tutorials-batch/specs/blog-posts.md @@ -0,0 +1,117 @@ +## ADDED Requirements + +### Requirement: Blog Post Frontmatter + +Each blog post MUST include YAML frontmatter with the following fields: `title`, `description`, `lead`, `slug`, `date`, `draft` (set to `false`), `weight`, `toc` (set to `true`), `categories`, `tags`, and `contributors`. + +#### Scenario: Valid blog post frontmatter +- **GIVEN** a new blog post Markdown file in `content/blog/` +- **WHEN** Hugo processes the file during build +- **THEN** the file MUST have all required frontmatter fields and `npm run build` MUST succeed without errors + +### Requirement: Blog Post Body Structure + +Each blog post MUST start body content with `##` (H2) headings. The `title` frontmatter generates H1. Posts MUST use ATX-style headings and fenced code blocks with language identifiers where applicable. + +#### Scenario: Correct heading hierarchy +- **GIVEN** a blog post with `title: "Example Title"` in frontmatter +- **WHEN** the post body begins +- **THEN** the first heading MUST be `##` (H2), not `#` (H1) + +### Requirement: Blog Post Content Quality + +Each blog post MUST follow the narrative arc defined in content pack BA-001: a problem statement, approach or evidence section, and a conclusion with a call to action. Posts MUST cover the key sections outlined in the corresponding GitHub issue. Key factual claims (version numbers, command names, configuration keys) SHOULD be verified against upstream repositories during implementation. + +#### Scenario: Blog post narrative structure +- **GIVEN** a completed blog post +- **WHEN** reviewed against the content pack BA-001 narrative arc requirement +- **THEN** the post MUST contain a problem statement or motivation section, an approach/evidence/walkthrough section, and a conclusion with a call to action or next steps + +### Requirement: CI Failure Classification Blog Post (#64) + +The site MUST include a blog post at `content/blog/ci-failure-classification.md` covering how `/review-pr` separates pre-existing CI failures from PR-caused regressions. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "ci-failure-classification"` +- **WHEN** a user navigates to `/blog/ci-failure-classification/` +- **THEN** the page MUST render with the full article content + +### Requirement: AGENTS.md Quality Blog Post (#65) + +The site MUST include a blog post at `content/blog/agents-md-quality.md` covering why AGENTS.md quality determines AI-generated code quality, including the `/agent-brief` command and 5-tier scoring rubric. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "agents-md-quality"` +- **WHEN** a user navigates to `/blog/agents-md-quality/` +- **THEN** the page MUST render with the full article content + +### Requirement: Dewey Knowledge Stores Blog Post (#69) + +The site MUST include a blog post at `content/blog/dewey-knowledge-stores.md` covering file-backed learnings and curated knowledge stores in Dewey v3.1.0. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "dewey-knowledge-stores"` +- **WHEN** a user navigates to `/blog/dewey-knowledge-stores/` +- **THEN** the page MUST render with the full article content + +### Requirement: Dewey Slash Command UX Blog Post (#72) + +The site MUST include a blog post at `content/blog/dewey-slash-command-ux.md` covering the `/dewey-store` slash command and its three interaction modes. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "dewey-slash-command-ux"` +- **WHEN** a user navigates to `/blog/dewey-slash-command-ux/` +- **THEN** the page MUST render with the full article content + +### Requirement: Pluggable LLM Providers Blog Post (#116) + +The site MUST include a blog post at `content/blog/pluggable-llm-providers.md` covering Dewey's pluggable Embedder/Synthesizer architecture with Ollama and Vertex AI support. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "pluggable-llm-providers"` +- **WHEN** a user navigates to `/blog/pluggable-llm-providers/` +- **THEN** the page MUST render with the full article content + +### Requirement: Gaze Baseline Comparison Blog Post (#150) + +The site MUST include a blog post at `content/blog/gaze-baseline-comparison.md` covering per-function CRAP regression detection and CI gate integration. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "gaze-baseline-comparison"` +- **WHEN** a user navigates to `/blog/gaze-baseline-comparison/` +- **THEN** the page MUST render with the full article content + +### Requirement: Council Review Action Blog Post (#191) + +The site MUST include a blog post at `content/blog/council-review-action.md` covering how the council-review-action composite GitHub Action brings the Divisor Council to CI. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "council-review-action"` +- **WHEN** a user navigates to `/blog/council-review-action/` +- **THEN** the page MUST render with the full article content + +### Requirement: Prompt Hardening Blog Post (#198) + +The site MUST include a blog post at `content/blog/prompt-hardening.md` covering prompt engineering techniques for compression resilience, including the vulnerability taxonomy and hardening techniques. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "prompt-hardening"` +- **WHEN** a user navigates to `/blog/prompt-hardening/` +- **THEN** the page MUST render with the full article content + +### Requirement: Multi-Platform Support Blog Post (#51) + +The site MUST include a blog post at `content/blog/multi-platform-support.md` covering how `uf init` scaffolds for both OpenCode and Cursor using a strategy pattern. + +#### Scenario: Post renders at correct URL +- **GIVEN** the blog post file exists with `slug: "multi-platform-support"` +- **WHEN** a user navigates to `/blog/multi-platform-support/` +- **THEN** the page MUST render with the full article content + +## MODIFIED Requirements + +None. + +## REMOVED Requirements + +None. diff --git a/openspec/changes/blog-tutorials-batch/specs/tutorials.md b/openspec/changes/blog-tutorials-batch/specs/tutorials.md new file mode 100644 index 0000000..db92ed3 --- /dev/null +++ b/openspec/changes/blog-tutorials-batch/specs/tutorials.md @@ -0,0 +1,95 @@ +## ADDED Requirements + +### Requirement: Tutorials Section Infrastructure + +The site MUST have a tutorials section at `content/docs/tutorials/` with a section index page (`_index.md`) and a navigation entry in `config/_default/menus/menus.en.toml` at weight 37. + +#### Scenario: Tutorials section appears in docs sidebar +- **GIVEN** the tutorials `_index.md` exists with proper frontmatter +- **WHEN** a user navigates to `/docs/tutorials/` +- **THEN** the section index page MUST render and tutorials MUST appear in the docs sidebar navigation + +#### Scenario: Navigation ordering is correct +- **GIVEN** the tutorials menu entry has weight 37 +- **WHEN** the docs sidebar renders +- **THEN** "Tutorials" MUST appear after "Reference" (weight 35) and before "Changelog" (weight 38) + +### Requirement: Tutorial Frontmatter + +Each tutorial MUST include YAML frontmatter with: `title`, `description`, `lead`, `date`, `draft` (set to `false`), `weight`, and `toc` (set to `true`). + +#### Scenario: Valid tutorial frontmatter +- **GIVEN** a new tutorial Markdown file in `content/docs/tutorials/` +- **WHEN** Hugo processes the file during build +- **THEN** the file MUST have all required frontmatter fields and `npm run build` MUST succeed + +### Requirement: Tutorial Body Structure + +Each tutorial MUST start body content with `##` (H2) headings. Tutorials SHOULD include step-by-step instructions with numbered sections, configuration examples in fenced code blocks, and prerequisite information. + +#### Scenario: Step-by-step structure +- **GIVEN** a tutorial page +- **WHEN** reviewed for instructional structure +- **THEN** the content MUST contain sections for: (1) prerequisites, (2) installation or setup steps, and (3) usage or verification steps + +### Requirement: Dewey Knowledge Stores Tutorial (#70) + +The site MUST include a tutorial at `content/docs/tutorials/dewey-knowledge-stores.md` covering knowledge store configuration, curation workflow, and semantic search setup. + +#### Scenario: Tutorial renders at correct URL +- **GIVEN** the tutorial file exists in the tutorials directory +- **WHEN** a user navigates to `/docs/tutorials/dewey-knowledge-stores/` +- **THEN** the page MUST render with the full tutorial content including prerequisites, configuration, and verification steps + +### Requirement: Dewey Provider Configuration Tutorial (#114) + +The site MUST include a tutorial at `content/docs/tutorials/dewey-provider-configuration.md` covering Ollama and Vertex AI provider setup for embedding and synthesis. + +#### Scenario: Tutorial renders at correct URL +- **GIVEN** the tutorial file exists in the tutorials directory +- **WHEN** a user navigates to `/docs/tutorials/dewey-provider-configuration/` +- **THEN** the page MUST render with configuration examples for both Ollama and Vertex AI providers + +### Requirement: Gaze CRAP Baseline CI Tutorial (#151) + +The site MUST include a tutorial at `content/docs/tutorials/gaze-crap-baseline-ci.md` covering baseline file generation, CI integration with GitHub Actions, and regression detection. + +#### Scenario: Tutorial renders at correct URL +- **GIVEN** the tutorial file exists in the tutorials directory +- **WHEN** a user navigates to `/docs/tutorials/gaze-crap-baseline-ci/` +- **THEN** the page MUST render with GitHub Actions workflow examples and baseline comparison setup + +### Requirement: Pinkman OSS Scout Tutorial (#45) + +The site MUST include a tutorial at `content/docs/tutorials/pinkman-oss-scout.md` covering the `/scout` command's four modes: discover, trend, audit, and report. + +#### Scenario: Tutorial renders at correct URL +- **GIVEN** the tutorial file exists in the tutorials directory +- **WHEN** a user navigates to `/docs/tutorials/pinkman-oss-scout/` +- **THEN** the page MUST render with usage examples for all four scout modes + +### Requirement: Onboard Customization Tutorial (#46) + +The site MUST include a tutorial at `content/docs/tutorials/onboard-customization.md` covering the `/onboard` command's three interview phases and hero experience customization. + +#### Scenario: Tutorial renders at correct URL +- **GIVEN** the tutorial file exists in the tutorials directory +- **WHEN** a user navigates to `/docs/tutorials/onboard-customization/` +- **THEN** the page MUST render with the three interview phases and customization options + +### Requirement: Build Validation + +After all content files are created, `npm run build` MUST succeed without errors. All new pages MUST appear in the site output. + +#### Scenario: Clean build with all new content +- **GIVEN** all 9 blog posts, 5 tutorials, and 1 section index have been created +- **WHEN** `npm run build` is executed +- **THEN** the build MUST complete successfully with exit code 0 and all 15 new pages MUST be present in the `public/` output directory + +## MODIFIED Requirements + +None. + +## REMOVED Requirements + +None. diff --git a/openspec/changes/blog-tutorials-batch/tasks.md b/openspec/changes/blog-tutorials-batch/tasks.md new file mode 100644 index 0000000..b4a7d66 --- /dev/null +++ b/openspec/changes/blog-tutorials-batch/tasks.md @@ -0,0 +1,47 @@ + + +## 1. Tutorials Section Infrastructure + +- [x] 1.1 Create `content/docs/tutorials/_index.md` with section frontmatter (title: "Tutorials", description, lead, date, draft: false, weight: 100, toc: false) +- [x] 1.2 Add tutorials navigation entry to `config/_default/menus/menus.en.toml` at weight 37 with identifier "tutorials" and url "/docs/tutorials/" + +## 2. Blog Posts + +All blog posts are independent files. Each follows the established frontmatter pattern from existing posts (title, description, lead, slug, date: 2026-08-23, draft: false, weight, toc: true, categories, tags, contributors). Content is sourced from the corresponding GitHub issue outline. + +- [x] 2.1 [P] Create `content/blog/ci-failure-classification.md` — How /review-pr separates signal from noise (issue #64, weight: 101) +- [x] 2.2 [P] Create `content/blog/agents-md-quality.md` — Why AGENTS.md quality determines code quality (issue #65, weight: 102) +- [x] 2.3 [P] Create `content/blog/dewey-knowledge-stores.md` — Dewey v3.1.0 knowledge stores (issue #69, weight: 103) +- [x] 2.4 [P] Create `content/blog/dewey-slash-command-ux.md` — Zero-code UX with /dewey-store (issue #72, weight: 104) +- [x] 2.5 [P] Create `content/blog/pluggable-llm-providers.md` — Dewey cloud-optional providers (issue #116, weight: 105) +- [x] 2.6 [P] Create `content/blog/gaze-baseline-comparison.md` — Per-function CRAP regression detection (issue #150, weight: 106) +- [x] 2.7 [P] Create `content/blog/council-review-action.md` — Divisor Council in GitHub Actions (issue #191, weight: 107) +- [x] 2.8 [P] Create `content/blog/prompt-hardening.md` — Prompt compression resilience (issue #198, weight: 108) +- [x] 2.9 [P] Create `content/blog/multi-platform-support.md` — uf init for OpenCode and Cursor (issue #51, weight: 109) + +## 3. Tutorials + +All tutorials are independent files under the tutorials section created in group 1. Each follows docs frontmatter conventions (title, description, lead, date: 2026-08-23, draft: false, weight, toc: true). Content is sourced from the corresponding GitHub issue outline. + +- [x] 3.1 [P] Create `content/docs/tutorials/dewey-knowledge-stores.md` — Setting up knowledge stores (issue #70, weight: 10) +- [x] 3.2 [P] Create `content/docs/tutorials/dewey-provider-configuration.md` — Configuring embedding/synthesis providers (issue #114, weight: 20) +- [x] 3.3 [P] Create `content/docs/tutorials/gaze-crap-baseline-ci.md` — CRAP baseline comparison in CI (issue #151, weight: 30) +- [x] 3.4 [P] Create `content/docs/tutorials/pinkman-oss-scout.md` — Getting started with /scout (issue #45, weight: 40) +- [x] 3.5 [P] Create `content/docs/tutorials/onboard-customization.md` — Getting started with /onboard (issue #46, weight: 50) + +## 4. Validation + +- [x] 4.1 Run `npm run build` and verify all 15 new pages appear in the `public/` output with no build errors +- [x] 4.2 Verify tutorials section appears in sidebar at correct position (between Reference and Changelog) and blog posts appear in blog listing via `npm run dev` visual check + + From 495ef026b4afc237989a19d1c674d975a6fa7e41 Mon Sep 17 00:00:00 2001 From: Jay Flowers Date: Sun, 23 Aug 2026 19:29:38 -0400 Subject: [PATCH 2/7] docs: add 9 blog posts and 5 tutorials Blog posts covering: - CI failure classification (#64) - AGENTS.md quality auditing (#65) - Dewey knowledge stores (#69) - Dewey slash command UX (#72) - Pluggable LLM providers (#116) - Gaze baseline comparison (#150) - Council review action (#191) - Prompt hardening (#198) - Multi-platform support (#51) Tutorials covering: - Dewey knowledge stores (#70) - Dewey provider configuration (#114) - Gaze CRAP baseline CI (#151) - Pinkman OSS Scout (#45) - Onboard customization (#46) Adds Tutorials section to navigation menu. --- config/_default/menus/menus.en.toml | 6 + content/blog/agents-md-quality.md | 155 ++++----- content/blog/ci-failure-classification.md | 66 ++++ content/blog/council-review-action.md | 85 +++++ content/blog/dewey-knowledge-stores.md | 186 ++++++++++ content/blog/dewey-slash-command-ux.md | 184 ++++++++++ content/blog/gaze-baseline-comparison.md | 155 +++++++++ content/blog/multi-platform-support.md | 101 ++++++ content/blog/pluggable-llm-providers.md | 153 ++++++++ content/blog/prompt-hardening.md | 178 ++++++++++ content/docs/tutorials/_index.md | 13 + .../docs/tutorials/dewey-knowledge-stores.md | 328 ++++++++++++++++++ .../tutorials/dewey-provider-configuration.md | 285 +++++++++++++++ .../docs/tutorials/gaze-crap-baseline-ci.md | 200 +++++++++++ .../docs/tutorials/onboard-customization.md | 312 +++++++++++++++++ content/docs/tutorials/pinkman-oss-scout.md | 234 +++++++++++++ 16 files changed, 2547 insertions(+), 94 deletions(-) create mode 100644 content/blog/ci-failure-classification.md create mode 100644 content/blog/council-review-action.md create mode 100644 content/blog/dewey-knowledge-stores.md create mode 100644 content/blog/dewey-slash-command-ux.md create mode 100644 content/blog/gaze-baseline-comparison.md create mode 100644 content/blog/multi-platform-support.md create mode 100644 content/blog/pluggable-llm-providers.md create mode 100644 content/blog/prompt-hardening.md create mode 100644 content/docs/tutorials/_index.md create mode 100644 content/docs/tutorials/dewey-knowledge-stores.md create mode 100644 content/docs/tutorials/dewey-provider-configuration.md create mode 100644 content/docs/tutorials/gaze-crap-baseline-ci.md create mode 100644 content/docs/tutorials/onboard-customization.md create mode 100644 content/docs/tutorials/pinkman-oss-scout.md diff --git a/config/_default/menus/menus.en.toml b/config/_default/menus/menus.en.toml index 7a5cfb7..d9ea669 100644 --- a/config/_default/menus/menus.en.toml +++ b/config/_default/menus/menus.en.toml @@ -22,6 +22,12 @@ identifier = "reference" url = "/docs/reference/" +[[docs]] + name = "Tutorials" + weight = 37 + identifier = "tutorials" + url = "/docs/tutorials/" + [[docs]] name = "Changelog" weight = 38 diff --git a/content/blog/agents-md-quality.md b/content/blog/agents-md-quality.md index 09f6456..079a8ce 100644 --- a/content/blog/agents-md-quality.md +++ b/content/blog/agents-md-quality.md @@ -1,140 +1,107 @@ --- title: "Your AI Agent's First Read — Why AGENTS.md Quality Determines Code Quality" -description: "AGENTS.md is the first file every AI coding agent reads. A weak one means the agent starts with wrong assumptions. /agent-brief creates or audits yours with a 5-tier scoring rubric." -lead: "Garbage in, garbage out. Your AGENTS.md is the prompt that shapes every line of AI-generated code. Audit it, do not guess." +description: "AGENTS.md is the first file every AI coding agent reads. A weak or missing AGENTS.md means wrong assumptions about conventions, build commands, and project structure — leading to code that compiles but doesn't fit." +lead: "Garbage in, garbage out. Your AGENTS.md is the prompt that shapes all agent output. /agent-brief tells you exactly where your project context is weak." slug: "agents-md-quality" -date: 2026-05-03T00:00:00+00:00 +date: 2026-08-23T00:00:00+00:00 draft: false -weight: 55 +weight: 102 toc: true categories: ["Engineering"] -tags: ["agents-md", "context", "quality", "agent-brief"] +tags: ["agents-md", "agent-brief", "developer-experience", "context"] contributors: ["Unbound Force"] --- -## The Problem +## The File Your Agent Reads Before Your Code -Every AI coding agent — Claude Code, Cursor, OpenCode, Copilot — reads a context file at the start of each session. That file tells the agent how to build the project, what conventions to follow, where the tests live, and what constraints to respect. In the Unbound Force ecosystem, this file is `AGENTS.md`. Other tools use `.cursorrules`, `CLAUDE.md`, or similar formats. The name varies; the problem is universal. +Every AI coding agent — Claude, GPT, Gemini, Copilot — follows the same pattern when it enters a repository. It looks for context files. `AGENTS.md` sits at the top of that list. Before the agent reads a single line of your source code, it reads `AGENTS.md` to learn your project's conventions, build commands, testing strategy, and architectural boundaries. -When this file is weak, missing, or stale, the agent starts every session with wrong assumptions. It guesses at build commands. It invents conventions that conflict with the team's standards. It writes code that compiles and passes linting but does not fit — wrong error handling patterns, wrong directory structure, wrong import organization. The code looks correct to a tool but wrong to a human reviewer. +This makes `AGENTS.md` the most consequential file in your repository for AI-assisted development. Not your README. Not your CI config. The file that tells the agent *how to behave in your codebase* determines whether the code it produces fits your project or fights it. -The fix is not "be more specific in your prompts." The fix is treating your project context file as production infrastructure — structured, auditable, and maintained. +A missing `AGENTS.md` means the agent guesses. A weak one means it guesses wrong with confidence. -## What Makes a Good AGENTS.md +## Garbage In, Garbage Out -A complete AGENTS.md has three tiers of sections, each serving a different purpose: +When your `AGENTS.md` is incomplete, the failure mode is subtle. The agent still produces code that compiles. It still writes tests that pass. But the code uses the wrong error handling pattern. The tests follow a naming convention nobody on the team recognizes. The new package lands in a directory that breaks your architectural layering. -### Tier 1: Essential Sections +These are not bugs. They are context failures. The agent did exactly what it was told — or more precisely, exactly what it *wasn't* told. Without explicit conventions, the agent falls back to generic best practices that may contradict your project's established patterns. You end up reviewing code that is technically correct but structurally wrong, and the review cycle burns more time than writing the code manually would have. -Every AGENTS.md needs these. Without them, the agent is guessing at fundamentals. +The cost compounds across sessions. Every agent session that starts with weak context produces output that drifts further from your project's norms. By the time you notice the drift, you have a codebase with three different error handling patterns and two competing package structures. -| Section | Purpose | What to Include | -|---------|---------|-----------------| -| **Project Overview** | What is this project? | Type (CLI, library, API), domain, license | -| **Build & Test Commands** | How do I build and test? | Exact commands with flags, in fenced code blocks | -| **Project Structure** | Where is everything? | Directory tree with annotations | -| **Code Conventions** | How should I write code? | Commit format, naming, error handling, import order | -| **Technology Stack** | What tools and versions? | Language versions, key dependencies, frameworks | +## What Makes an AGENTS.md Effective -These five sections are the minimum. An agent with all five can produce code that builds, follows conventions, and lands in the right directory. +An effective `AGENTS.md` answers the questions an agent asks implicitly every time it starts working. What build system does this project use? What does the test command look like? Where do new files go? What naming conventions apply? What are the non-negotiable rules? -### Tier 1C: Context-Sensitive Sections +Concretely, a strong `AGENTS.md` covers these structural elements: -These sections are triggered by project signals. They are essential *when applicable* but irrelevant otherwise. +- **Build and dev commands** — the exact commands to build, test, lint, and run the project +- **Project structure** — a directory tree showing where code, tests, config, and assets live +- **Code style guidelines** — naming conventions, import ordering, error handling patterns +- **Testing conventions** — how tests are named, organized, and run +- **Behavioral constraints** — rules the agent must never violate, regardless of what it thinks is "better" +- **Active technologies** — the specific frameworks, libraries, and versions in use -- **Constitution / Governance**: Only needed when the project has a constitution file (`.specify/memory/constitution.md`). Summarizes the governing principles that all work must align with. -- **Spec Framework**: Only needed when the project uses Speckit (`specs/` directory) or OpenSpec (`openspec/config.yaml`). Describes the specification workflow and pipeline stages. +Each missing section is a gap the agent fills with assumptions. Some assumptions will be right. Enough will be wrong to create real friction. -An AGENTS.md that omits a Tier 1C section when the trigger exists is incomplete — the agent will not know about governance constraints or spec requirements that other tools enforce. - -### Tier 2: Advanced Sections - -These sections differentiate a strong AGENTS.md from an adequate one. They capture the institutional knowledge that takes weeks to discover. - -| Section | Purpose | -|---------|---------| -| **Architecture** | Patterns, design decisions, module boundaries | -| **Testing Conventions** | Test organization, fixture patterns, coverage expectations | -| **Git & Workflow** | Branching strategy, PR requirements, branch protection | -| **Behavioral Constraints** | Things agents must NEVER do (often more impactful than positive instructions) | - -A Behavioral Constraints section is particularly valuable. Negative instructions like "never modify coverage thresholds to make tests pass" and "never commit directly to main" prevent entire categories of agent mistakes. +## Audit, Don't Guess -## The 5-Tier Scoring Rubric +The problem with `AGENTS.md` quality is that it is invisible until something goes wrong. You do not know your build commands section is missing until an agent runs `make build` on a project that uses `npm run build`. You do not know your testing conventions are vague until an agent writes table-driven tests in a project that uses behavior-driven specs. -How do you know if your AGENTS.md is good enough? The `/agent-brief` command uses a deterministic scoring rubric: +`/agent-brief` makes this visible. It audits your `AGENTS.md` against 12 structural checks — section headers, code blocks, line count, bridge file references — and scores the result on a 5-tier rubric: -| Score | Criteria | -|-------|----------| -| **Excellent** | 5/5 Tier 1 + 4/4 Tier 2 + all applicable Tier 1C | -| **Strong** | 5/5 Tier 1 + 2-3/4 Tier 2 | -| **Adequate** | 4-5/5 Tier 1 | -| **Weak** | 2-3/5 Tier 1 | -| **Missing** | 0-1/5 Tier 1 | +| Tier | Score | Meaning | +|------|-------|---------| +| **Excellent** | 90–100 | Comprehensive context, agents operate with high autonomy | +| **Strong** | 70–89 | Solid foundation, minor gaps that rarely cause issues | +| **Adequate** | 50–69 | Functional but agents will make avoidable mistakes | +| **Weak** | 25–49 | Significant gaps, expect frequent context failures | +| **Missing** | 0–24 | Agents are guessing on nearly everything | -If Tier 1C sections are applicable (the project has a constitution or spec framework) but missing, the score is downgraded by one level. An otherwise "Strong" AGENTS.md becomes "Adequate" if it ignores governance constraints that the project enforces. +Before `/agent-brief`, the check was binary: does `AGENTS.md` exist or not? That distinction is almost useless. A 10-line `AGENTS.md` that says "this is a Go project, run `go test`" exists, but it leaves the agent blind to your package structure, naming conventions, CI requirements, and architectural boundaries. The granular scoring replaces a yes/no gate with actionable diagnostics. -The scoring is structural, not subjective. It counts section headers, checks for code blocks in the Build section, verifies that directory trees match the actual filesystem, and confirms that constitution references exist when a constitution is present. Twelve checks in total — no AI judgment involved in the score. +Each check that fails comes with a specific recommendation. Not "improve your AGENTS.md" but "add a Project Structure section with a directory tree" or "include fenced code blocks for build commands so agents can execute them directly." -## Audit, Don't Guess +## Context-Sensitive, Not One-Size-Fits-All -```text -/agent-brief audit -``` +Not every project uses the same tools. A solo developer's weekend project does not need a constitution section. A team running the full Speckit pipeline does. `/agent-brief` adapts its checks to what your project actually uses. -The audit command reads your existing AGENTS.md and produces a quality report: +When `/agent-brief` detects a `.specify/memory/constitution.md` file, it checks whether your `AGENTS.md` references the constitution and explains its authority. When it detects a `specs/` directory, it checks for spec workflow documentation. When neither exists, those checks are skipped entirely — no false negatives for tools you have not adopted. -- **Section coverage**: Which Tier 1 / 1C / 2 sections are present vs. missing -- **Quality metrics**: Line count, build code blocks, directory tree accuracy, staleness checks -- **Overall score**: One of the 5 tiers, with justification -- **Recommendations**: For each missing section, generated content you can review and apply +This context sensitivity matters because prescriptive checklists create noise. If every project gets flagged for missing constitution documentation, teams without constitutions learn to ignore the audit. By scoping checks to detected project signals — `go.mod`, `Makefile`, `.github/workflows/`, `package.json` — the audit stays relevant regardless of project size or tooling choices. -The audit is read-only — it does not modify your file. You decide what to accept. +## The 12 Structural Checks -## Create from Project Signals +`/agent-brief` evaluates your `AGENTS.md` across 12 dimensions that map to the questions agents ask most frequently: ```text -/agent-brief create +1. Project Overview — What does this project do? +2. Build & Dev Commands — How do I build, test, and run it? +3. Project Structure — Where do files go? +4. Code Style Guidelines — What conventions apply? +5. Testing Conventions — How are tests written and organized? +6. Behavioral Constraints — What must I never do? +7. Active Technologies — What frameworks and versions are in use? +8. Recent Changes — What changed recently that I should know about? +9. Common Tasks — Step-by-step guides for frequent operations +10. CI/CD — What does the pipeline check? +11. Constitution Reference — (conditional) Where is the governance doc? +12. Spec Workflow Reference — (conditional) How does the spec pipeline work? ``` -When no AGENTS.md exists, `/agent-brief` analyzes your project and generates one from actual project data: +Each check looks for more than a section header. It verifies that the section contains substantive content — code blocks for commands, directory trees for structure, concrete rules for constraints. A section that says "follow standard Go conventions" scores lower than one that specifies `gofumpt` formatting, `golangci-lint` with a named config, and `go test -race -count=1 ./...` as the test command. -- **`go.mod`**, **`package.json`**, **`Cargo.toml`** → language, dependencies, versions -- **`Makefile`**, **`.github/workflows/`** → exact build, test, and lint commands (CI files are the source of truth) -- **`.golangci.yml`**, **`ruff.toml`**, **`.eslintrc`** → linter rules and conventions -- **`README.md`**, **`LICENSE`**, **`.git/config`** → project description, license, organization -- **`.specify/memory/constitution.md`**, **`specs/`**, **`openspec/`** → governance and spec framework (Tier 1C triggers) +## Beyond Unbound Force -The generated file has two quality levels: Tier 1 sections are filled from actual project data (concrete commands, real directory trees, detected conventions). Tier 2 sections are stubs with detailed TODO comments explaining what to fill and why it matters. The result is a complete skeleton that you can review and flesh out. +This problem is not specific to any particular agent framework. Every AI coding tool — whether it is an IDE extension, a CLI agent, or a chat-based assistant — performs better with explicit project context. The `AGENTS.md` pattern has emerged as a de facto standard across the industry precisely because the alternative (letting agents infer context from code alone) produces inconsistent results. -## Bridge Files +If you use AI coding agents in any capacity, auditing your project context is one of the highest-leverage improvements you can make. The time investment is small — most `AGENTS.md` files are 100–300 lines — and the payoff is immediate. Every agent session that starts with strong context produces output that requires less review, fewer corrections, and fewer "why did it do that?" moments. -AGENTS.md is the canonical project context file, but different AI tools read different files. `/agent-brief` ensures cross-tool compatibility by verifying bridge files: - -- **CLAUDE.md**: Should contain `@AGENTS.md` to import the project context into Claude Code sessions -- **.cursorrules**: Should reference AGENTS.md for Cursor IDE integration - -Bridge file creation is handled by `uf init`. If bridge files are missing or misconfigured, `/agent-brief` reports the status and suggests running `uf init` to create them. - -## This Applies to Every AI Coding Tool - -AGENTS.md is not an Unbound Force concept — it is a convention adopted across multiple AI coding tools. Claude Code reads `CLAUDE.md` and `AGENTS.md`. Cursor reads `.cursorrules`. Copilot reads context from repository structure. The names differ, but the principle is the same: the quality of your context file determines the quality of your AI-generated code. - -The section taxonomy (Tier 1 / 1C / 2), the scoring rubric, and the structural checks apply regardless of which tool you use. If your `.cursorrules` file has no build commands and no project structure, your Cursor agent is guessing — just like an OpenCode agent with a weak AGENTS.md. +The pattern extends beyond `AGENTS.md` itself. Any file that shapes agent behavior — convention packs, constitution documents, spec templates — benefits from the same audit discipline. If the file is a prompt (and context files are prompts), treat it with the same rigor you would apply to production code. ## Get Started -Install the Unbound Force CLI and audit your project: - -```bash -brew install unbound-force/tap/unbound-force -/agent-brief audit -``` - -Find out where your project context is weak. Fix it. Watch the quality of AI-generated code improve. +Run `/agent-brief` in your project to see where your context stands. The audit takes seconds and produces a scored report with specific recommendations for each gap it finds. -## See Also +If you do not have an `AGENTS.md` yet, `/agent-brief` generates one from your project's existing signals — `go.mod`, `package.json`, `Makefile`, CI workflows, and README. The generated file is a starting point, not a finished product. Review it, refine the conventions to match your team's actual practices, and commit it alongside your code. -- [Common Workflows](/docs/getting-started/common-workflows/) -- `/agent-brief` create and audit documentation -- [Quick Start](/docs/getting-started/quick-start/) -- Install and verify the toolchain -- [Developer Guide](/docs/getting-started/developer/) -- Daily workflow with the `uf` CLI +Your agents are reading `AGENTS.md` whether you wrote a good one or not. Make sure what they read is worth following. diff --git a/content/blog/ci-failure-classification.md b/content/blog/ci-failure-classification.md new file mode 100644 index 0000000..8f157ef --- /dev/null +++ b/content/blog/ci-failure-classification.md @@ -0,0 +1,66 @@ +--- +title: "Your CI Failed — But Was It Your Fault? How /review-pr Separates Signal from Noise" +description: "When CI fails on a PR, developers waste time investigating failures that predate their changes. /review-pr classifies each failure as PR-caused or pre-existing — one command replaces hours of forensic debugging." +lead: "Not your fault? Not your problem. One command classifies every CI failure as PR-caused or pre-existing, so you stop debugging test flakes you didn't create." +slug: "ci-failure-classification" +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 101 +toc: true +categories: ["Engineering"] +tags: ["review-pr", "CI", "code-review", "automation"] +contributors: ["Unbound Force"] +--- + +## The Red X That Wastes Your Morning + +You open your pull request. CI is red. Your stomach drops — and then you spend the next hour discovering that the failure has nothing to do with your changes. A flaky integration test that fails one run in ten. A lint violation introduced three PRs ago. A dependency warning that nobody addressed last sprint. You didn't break anything, but you're the one staring at log output trying to prove it. + +This is the hidden tax of continuous integration. CI pipelines report pass or fail, but they don't tell you *whose* fault it is. Every red build lands on the PR author's desk, regardless of whether the failure existed before their branch diverged from main. The result is a forensic debugging ritual: compare the failing test against the base branch, check if the lint rule was already violated, search Slack for "is this test flaky?" — all before you can address the actual review feedback on your code. + +The cost compounds across a team. Senior engineers develop intuition for which failures to ignore, but junior developers investigate every red check. Across an organization, hundreds of engineering hours per quarter evaporate into diagnosing failures that predate the current PR. + +## What If CI Told You Who Broke It? + +The `/review-pr` command takes a different approach. Instead of dumping a wall of failures and leaving you to sort them out, it fetches CI results from your pull request and classifies each failure into one of two buckets: **PR-caused** or **pre-existing**. + +The classification works by comparing the failure against the base branch. If a test also fails on main, it's pre-existing — not your regression. If a lint violation exists in files you didn't touch, it's pre-existing. If a check fails only on your branch, in code your commits modified, it's PR-caused and needs your attention. + +``` +/review-pr +``` + +That's the entire invocation. One command fetches the CI results from GitHub, runs local analysis tools against your changes, applies AI judgment to classify ambiguous cases, and produces a structured report. No manual log diving. No cross-referencing against the base branch. No asking teammates if a test is "known flaky." + +## Two Buckets, Two Workflows + +For **PR-caused failures**, `/review-pr` doesn't stop at classification. It runs the same local tools that CI uses — linters, test suites, static analyzers — and produces actionable findings with file paths, line numbers, and explanations. The AI layer adds context that raw tool output lacks: why the failure matters, what the fix looks like, and whether the issue is a real bug or a style violation. + +For **pre-existing failures**, the command offers to create a fix branch. Instead of ignoring the problem or filing a ticket that sits in the backlog for months, `/review-pr` proposes a concrete path forward: a separate branch that addresses the pre-existing issue without polluting your PR's diff. This is the "fix it forward" philosophy — acknowledge the problem, isolate it from the current work, and make progress on both fronts. + +The separation matters because it changes the conversation in code review. Reviewers no longer need to ask "is this CI failure related to your changes?" The classification is already done. Review cycles get shorter. Authors spend time on the feedback that matters — the design questions, the edge cases, the architectural concerns — instead of defending themselves against failures they didn't introduce. + +## Lessons from Building It: 12 Tool Calls and 6 Reliability Fixes + +The `/review-pr` command itself went through the gauntlet it was designed to solve. During PR #139, the original implementation wasted 12 tool calls due to 6 reliability issues — GitHub API pagination edge cases, malformed check-run queries, and timeout handling gaps. Every one of those issues was discovered, classified, and fixed in a reliability follow-up. + +The experience validated the core design principle: CI causality analysis is harder than it looks, but the pattern is broadly useful. The same classification logic that separates "your fault" from "not your fault" applies to any project with a CI pipeline and a pull request workflow. The technique isn't specific to Unbound Force's toolchain — it's a general-purpose pattern for any team drowning in CI noise. + +Three specific reliability improvements emerged from that process. First, pagination: GitHub's check-runs API paginates at 30 results, and the initial implementation silently dropped failures beyond the first page. Second, rate limiting: aggressive parallel API calls triggered GitHub's secondary rate limits, requiring exponential backoff. Third, ambiguous classification: some failures (like timeout-based flakes) required heuristic judgment rather than deterministic comparison, which the AI layer handles by examining failure patterns across recent runs. + +## The Complete Review Lifecycle + +The `/review-pr` command is one half of a review lifecycle. The other half is `/review-council`, which runs before you push — a multi-persona review that catches issues before they reach CI. Together, the two commands form a complete loop: + +1. **Before pushing**: Run `/review-council` to get pre-PR feedback from multiple review perspectives (security, architecture, testing, operations). Fix findings before your code reaches the remote. +2. **After creating the PR**: Run `/review-pr` to classify CI results, separate signal from noise, and get actionable findings on any regressions your changes introduced. + +The pre-push review catches design issues, missing tests, and convention violations while the code is still local and cheap to change. The post-PR review handles the integration reality — how your changes interact with CI, with the base branch, and with the broader test suite. Neither command replaces the other. They address different failure modes at different points in the development cycle. + +## Stop Debugging Someone Else's Failures + +Every minute spent investigating a pre-existing CI failure is a minute not spent shipping the feature your team is waiting for. The `/review-pr` command eliminates that waste by answering the question CI never answers: *was this your fault?* + +The pattern is straightforward. Run one command after creating your PR. Get a classified report that separates your regressions from inherited problems. Fix what's yours, forward what isn't, and move on. + +If your team loses hours per week to CI forensics, try `/review-pr` on your next pull request. Check the [Unbound Force documentation](/docs/getting-started/) to get started, or explore the [review-pr command source](https://github.com/unbound-force/unbound-force) to see how causality classification works under the hood. diff --git a/content/blog/council-review-action.md b/content/blog/council-review-action.md new file mode 100644 index 0000000..cbacfef --- /dev/null +++ b/content/blog/council-review-action.md @@ -0,0 +1,85 @@ +--- +title: "AI Code Review in CI — How council-review-action Brings the Divisor Council to GitHub Actions" +description: "The Divisor Council's multi-persona AI code review now runs as a composite GitHub Action. Fork-safe, auto-discovering personas, and producing structured inline comments on every PR." +lead: "Five AI reviewers, one GitHub Action. council-review-action brings the Divisor Council's multi-persona code review to your CI pipeline — fork-safe, structured, and discoverable." +slug: "council-review-action" +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 107 +toc: true +categories: ["Engineering"] +tags: ["divisor", "code-review", "github-actions", "CI", "automation"] +contributors: ["Unbound Force"] +--- + +## The Problem with AI Code Review in CI + +Most AI code review integrations follow the same pattern: drop an API key into your workflow, pipe the diff to a model, and post whatever comes back as a PR comment. The result is a wall of unstructured text that developers scroll past. The review lacks perspective — a single model producing a single opinion, with no specialization and no structure. + +The Divisor Council solves this locally. Five AI personas — The Guard, The Architect, The Adversary, The SRE, and The Testing Specialist — each review code through a different lens. But running the council required a local setup with OpenCode and the right agent configurations. That meant the review happened on the developer's machine, not in CI where every PR gets consistent coverage. + +`council-review-action` bridges that gap. It packages the Divisor Council as a composite GitHub Action that runs on every pull request, producing structured inline comments tied to specific lines of code. + +## Fork-Safe by Design: The Three-Workflow Chain + +GitHub Actions restricts secret access for pull requests from forks — a security measure that breaks most AI review integrations. Fork PRs cannot access repository secrets, so any workflow that calls an LLM API fails silently or crashes loudly. + +`council-review-action` uses a three-workflow chain pattern to work around this constraint without compromising security. The first workflow, `pull_request`, runs in the fork's context with no secret access. It performs the diff extraction, context gathering, and artifact preparation — all operations that require no credentials. The second workflow, `workflow_run`, triggers after the first completes and runs in the base repository's context where secrets are available. This workflow picks up the prepared artifacts and executes the LLM calls. The third step posts the review comments back to the PR using the base repository's `GITHUB_TOKEN`. + +This separation means fork contributors get the same review quality as maintainers. No secrets leak to fork contexts. No special configuration is needed for external contributors. The review runs automatically on every PR regardless of its origin. + +## Auto-Discovery: Your Personas or Ours + +The action discovers Divisor personas by scanning the repository's `.opencode/agents/` directory for agent configuration files. If your project defines custom personas — perhaps a Database Specialist for a data-heavy application or a Compliance Reviewer for regulated industries — the action picks them up automatically. No configuration flags, no manifest files, no explicit persona lists. + +When no custom personas exist, the action falls back to its bundled defaults: the five standard Divisor Council members. Each persona carries its own review focus, severity calibration, and output format expectations. The Guard checks for security vulnerabilities and credential exposure. The Architect evaluates structural decisions and dependency flow. The Adversary stress-tests edge cases and failure modes. The SRE examines operational concerns — logging, monitoring, graceful degradation. The Testing Specialist assesses coverage gaps and test quality. + +This auto-discovery pattern means teams adopt the action with zero configuration and customize it by adding agent files they already know how to write. + +## The Diff Annotation Pipeline + +Raw diffs are noisy. They contain file mode changes, lock file updates, and generated code that no reviewer — human or AI — should spend tokens on. Feeding an unprocessed diff to an LLM wastes context window and produces findings against code that does not matter. + +The diff annotation pipeline applies three transformations before any persona sees the code. First, noise filtering removes binary files, lock files, generated artifacts, and files matching configurable ignore patterns. Second, line numbering maps every diff hunk to its exact file and line position in the PR, enabling precise inline comment placement. Third, the output is reformatted into an LLM-friendly structure that preserves enough surrounding context for each change without exhausting the model's context window. + +The result is a focused, annotated diff where every line carries its file path and position. When a persona identifies an issue, it references the exact line — and the action maps that reference back to the GitHub PR's diff view for inline comment placement. + +## Pre-Fetched PR Context + +Code does not exist in isolation. A PR that introduces a new dependency matters differently if CI is already failing. A refactoring PR reads differently when linked issues explain the motivation. A change that duplicates an existing review comment wastes everyone's time. + +Before invoking any persona, the action pre-fetches three categories of context. CI check status tells personas whether the build is green, which tests are failing, and whether linting has already flagged issues. Existing review comments prevent personas from duplicating feedback that human reviewers or previous action runs have already posted. Linked issues and PR description provide the "why" behind the change, helping personas distinguish intentional trade-offs from oversights. + +This context is injected into each persona's prompt alongside the annotated diff. The personas review code with the same situational awareness a human reviewer would have after reading the PR description, checking CI, and scanning existing comments. + +## Structured Output: JSON with Line Validation + +Unstructured LLM output is the root cause of low-quality AI reviews. When a model returns free-form text, the integration has no reliable way to extract file paths, line numbers, severity levels, or actionable suggestions. The result is a single monolithic comment that developers ignore. + +Each persona in `council-review-action` produces structured JSON output. Every finding includes a file path, line number, severity level (CRITICAL, HIGH, MEDIUM, LOW), the persona that raised it, a description of the issue, and a suggested fix when applicable. The action validates each finding's line number against the actual diff — if a persona references a line that does not exist in the changed code, the finding is dropped rather than posted as a confusing orphaned comment. + +Valid findings are posted as inline PR comments at the exact line of code they reference. Developers see each finding in context, right next to the code it concerns, with clear attribution to the persona that raised it. The structured format also enables downstream tooling: filtering by severity, tracking finding trends across PRs, and measuring persona accuracy over time. + +## Security: Defense in Depth + +Running LLM-based review on untrusted code — especially from fork PRs — introduces prompt injection risk. A malicious contributor could craft code comments, variable names, or documentation strings designed to manipulate the reviewing model into approving vulnerable code or leaking secrets. + +`council-review-action` maintains a security risk register that catalogs known attack vectors and their mitigations. The three-workflow chain is the first layer: fork code never executes in a context with secret access. The diff annotation pipeline is the second layer: by controlling what the model sees, the action limits the attack surface to the diff content itself. Persona prompts include injection-resistant framing that instructs the model to treat all diff content as untrusted input, not as instructions. + +The risk register is a living document. Each identified risk carries a severity rating, a description of the attack vector, the current mitigation, and the residual risk after mitigation. This transparency lets adopters make informed decisions about their threat model rather than trusting a black-box claim of "secure by default." + +## ADR-001: Why OpenCode over Claude Code CLI + +The action needed a runtime to orchestrate LLM calls with agent configurations, tool access, and structured output parsing. Two candidates emerged: Claude Code CLI (Anthropic's official tool) and OpenCode (the open-source AI coding assistant). + +Claude Code CLI offers tight integration with Anthropic's models but locks the action to a single provider. It requires a specific authentication flow that complicates the three-workflow chain pattern. Its agent configuration format differs from the `.opencode/agents/` convention that Unbound Force projects already use, meaning persona auto-discovery would require a translation layer. + +OpenCode supports multiple LLM providers, uses the same agent configuration format the Divisor Council already defines, and runs as a straightforward CLI that fits naturally into composite action steps. The decision — documented as ADR-001 in the action's `docs/decisions.md` — chose OpenCode for provider flexibility, configuration compatibility, and alignment with the existing Unbound Force toolchain. Teams that already use OpenCode locally get the same agent behavior in CI without any configuration drift. + +## What This Means for Your Workflow + +`council-review-action` turns the Divisor Council from a local developer tool into a CI-native review gate. Every PR gets reviewed by five specialized personas. Every finding lands as an inline comment at the exact line of code. Fork contributors get the same review quality as maintainers. Custom personas are discovered automatically from your existing agent configurations. + +The action is available in the `unbound-force/unbound-force` repository under `council-review-action/`. Add it to your workflow, configure your LLM provider credentials as repository secrets, and the council convenes on every pull request. + +To get started, check out the [council-review-action README](https://github.com/unbound-force/unbound-force/tree/main/council-review-action) for installation instructions, configuration options, and examples of the three-workflow chain pattern in practice. If you are already using the Divisor Council locally, your personas will carry over to CI with no additional setup. diff --git a/content/blog/dewey-knowledge-stores.md b/content/blog/dewey-knowledge-stores.md new file mode 100644 index 0000000..a1378f1 --- /dev/null +++ b/content/blog/dewey-knowledge-stores.md @@ -0,0 +1,186 @@ +--- +title: "Your AI Agent's Memory Survives Database Deletion — Dewey v3.1.0 Knowledge Stores" +description: "Dewey v3.1.0 introduces curated knowledge stores — an automated pipeline that extracts structured knowledge from indexed sources using LLM analysis. Paired with file-backed learnings that survive database deletion." +lead: "Delete the database, restart Dewey, and every learning is back. File-backed persistence plus automated curation turn raw documents into structured, quality-scored knowledge." +slug: "dewey-knowledge-stores" +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 103 +toc: true +categories: ["Engineering"] +tags: ["dewey", "knowledge-stores", "curation", "semantic-search"] +contributors: ["Unbound Force"] +--- + +## The Fragility Problem + +AI agents accumulate knowledge across sessions. Decisions made during code review, patterns discovered while debugging, gotchas encountered during deployment — all of it feeds back into future work. In most agent frameworks, that knowledge lives in a single SQLite database. Delete it, corrupt it, or move to a new machine, and every learning is gone. + +The loss of structured knowledge is only half the problem. Organizations generate vast amounts of unstructured content — meeting notes, Slack exports, GitHub discussions, design documents — that contain critical decisions and patterns buried in prose. No agent can extract those insights without reading every document, every time. The knowledge exists, but it's locked inside formats that resist automated extraction. + +This is the third post in our Dewey blog arc. In [The Librarian vs The Index](/blog/dewey-librarian-vs-index/), we explored why semantic search alone isn't enough. In [How Dewey Became a Knowledge Curator](/blog/dewey-knowledge-curator/), we showed how Dewey moved beyond retrieval into active knowledge management. Now we tackle the two remaining gaps: durability and automated extraction. + +## Two Complementary Solutions + +Dewey v3.1.0 addresses both problems with a pair of features that work together but solve distinct failure modes. + +### File-Backed Learnings + +Every `store_learning` call now dual-writes. The learning goes into SQLite for fast semantic search, and simultaneously to a plain markdown file at `.uf/dewey/learnings/{tag}-{seq}.md`. These files are plain text, human-readable, and version-controllable with git. + +Delete the database. Restart Dewey. On startup, the file-backed persistence layer scans the learnings directory and re-ingests every file. Embeddings are regenerated, metadata is restored, and semantic search works as if nothing happened. The database becomes a cache, not the source of truth. + +This design means agent knowledge travels with the repository. Clone the repo on a new machine, start Dewey, and the full knowledge base is available. No database migration, no backup restoration, no cloud sync. + +### Curated Knowledge Stores + +File-backed learnings solve durability for knowledge that agents create. But what about knowledge that already exists in documents no agent wrote? Meeting notes that record an architectural decision. A GitHub discussion that resolves a design trade-off. A Slack thread where the team agreed on a naming convention. + +Knowledge stores automate the extraction of structured knowledge from these raw sources. You configure a `.uf/dewey/knowledge-stores.yaml` that maps indexed sources to named stores, then run `dewey curate`. An LLM reads each document and extracts decisions, patterns, and facts — each tagged with source traceability, confidence scoring, and quality flags. + +The LLM here is a structured extraction tool, not an "intelligent curator." It follows explicit extraction rules defined in the store configuration. It scores its own confidence. It flags ambiguity. The output is deterministic enough to diff, review, and version-control. + +## The Workflow + +### Step 1: Configure Knowledge Stores + +A `knowledge-stores.yaml` file defines which indexed sources feed into which stores, and what extraction rules apply: + +```yaml +stores: + architecture-decisions: + description: "Architectural decisions from design docs and discussions" + sources: + - id: github-discussions + filter: "label:architecture" + - id: design-docs + path: "docs/architecture/**/*.md" + extraction: + categories: + - decision + - pattern + - constraint + min_confidence: 0.7 + + operational-runbooks: + description: "Operational patterns from incident reports and postmortems" + sources: + - id: incident-reports + path: "docs/incidents/**/*.md" + extraction: + categories: + - pattern + - gotcha + - procedure + min_confidence: 0.6 +``` + +Each store targets a specific knowledge domain. The `sources` field maps to Dewey's indexed content — the same sources you configure in `.uf/dewey/sources.yaml`. The `extraction` block controls what the LLM looks for and the minimum confidence threshold for inclusion. + +### Step 2: Run Curation + +```bash +dewey curate +``` + +Dewey processes each configured store. For every source document, the LLM extracts structured knowledge items. Incremental curation (`dewey curate --incremental`) processes only documents that changed since the last run, keeping curation fast for large knowledge bases. + +Background curation can be configured to run automatically when new content is indexed, keeping knowledge stores current without manual intervention. + +### Step 3: Review Curated Knowledge + +Each extracted knowledge item is written as a markdown file with YAML frontmatter that captures provenance and quality metadata: + +```yaml +--- +tag: architecture-decisions +category: decision +confidence: 0.85 +quality_flags: + - explicit_decision + - multiple_sources +sources: + - id: github-discussions/142 + title: "RFC: Event sourcing for audit trail" + excerpt: "After evaluating CQRS vs traditional CRUD, the team decided..." + - id: design-docs/adr-007.md + title: "ADR-007: Event Sourcing for Compliance" + excerpt: "Decision: Adopt event sourcing for all compliance-related..." +tier: curated +--- + +The audit trail uses event sourcing rather than CRUD operations. +This decision was driven by compliance requirements that mandate +a complete, immutable history of all state changes. The team +evaluated CQRS as an alternative but rejected it due to the +additional operational complexity of maintaining separate read +and write models. +``` + +Every curated fact traces back to its source documents. The `confidence` score reflects how explicitly the source stated the knowledge — a direct "we decided X" scores higher than an implied preference. Quality flags indicate whether the extraction found corroboration across multiple sources, whether the decision was explicitly stated, or whether the LLM flagged ambiguity. + +### Step 4: File-Backed Recovery + +The durability guarantee applies to both agent-created learnings and curated knowledge. Here's the recovery scenario: + +```bash +# Store learnings during normal operation +# (via MCP tool calls from any agent) +dewey store-learning --tag auth "OAuth2 PKCE flow required for CLI tools" +dewey store-learning --tag deploy "Blue-green deploys need 30s drain period" + +# Verify learnings exist +ls .uf/dewey/learnings/ +# auth-1.md deploy-1.md + +# Disaster: database deleted +rm .uf/dewey/dewey.db + +# Restart Dewey +dewey serve + +# All learnings are automatically re-ingested from files +dewey search "OAuth2 CLI" +# Returns: "OAuth2 PKCE flow required for CLI tools" (confidence: 1.0) +``` + +No manual intervention. No restore-from-backup workflow. The files are the backup, and they're always in sync because they're written at the same time as the database entry. + +## How This Compares + +The combination of file-backed persistence and curated extraction differs from typical RAG (Retrieval-Augmented Generation) pipelines in several dimensions: + +| Dimension | Typical RAG | Dewey v3.1.0 | +|-----------|-------------|--------------| +| Knowledge quality | Retrieves fragments without quality assessment | Extracts with confidence scoring and quality flags | +| Provenance | Chunk ID, sometimes source file | Full source traceability to specific documents and excerpts | +| Trust model | All retrieved content treated equally | 4-tier trust system (authored → curated → draft → untrusted) | +| Data locality | Usually cloud-hosted vector DB | Local-only (SQLite + Ollama) | +| Durability | Database is the single source of truth | File-backed dual-write survives database deletion | +| Portability | Tied to the vector DB instance | Git-compatible files travel with the repository | + +RAG pipelines optimize for retrieval speed. Dewey optimizes for knowledge quality. A RAG system returns the most similar chunks to your query. Dewey returns knowledge items that have been extracted, scored, traced to sources, and assigned a trust tier. The difference matters when agents make decisions based on retrieved context — confidence scoring and provenance let the agent weigh evidence rather than treating all retrieved content as equally authoritative. + +## What This Enables + +File-backed learnings and curated knowledge stores unlock workflows that weren't practical before. + +**Team knowledge sharing.** Because learnings are plain markdown files in a git-tracked directory, teams can share knowledge across machines by pushing and pulling the `.uf/dewey/learnings/` directory. A pattern discovered by one developer's agent is available to every team member's agent after a `git pull`. + +**Knowledge auditing.** Every curated fact has a source trail. When a decision is questioned six months later, the provenance metadata points back to the original discussion, RFC, or meeting notes. No more "we decided this at some point but nobody remembers why." + +**Incremental refinement.** Curated knowledge items can be promoted from `draft` to `curated` to `validated` tier as humans review and confirm them. The trust tier affects how agents weight the knowledge during retrieval — validated knowledge ranks higher than draft extractions. + +## Try It + +Dewey v3.1.0 is available now. To set up knowledge stores in your project, follow the companion tutorial: [Setting Up Knowledge Stores](/docs/tutorials/dewey-knowledge-stores/). + +The tutorial walks through configuring your first knowledge store, running curation against your project's documentation, and verifying the file-backed recovery guarantee. Start with a single store targeting your project's design documents or ADRs — that's where the highest-value knowledge tends to live. + +To install or upgrade Dewey: + +```bash +go install github.com/unbound-force/dewey/cmd/dewey@v3.1.0 +``` + +Read the [v3.1.0 release notes](https://github.com/unbound-force/dewey/releases/tag/v3.1.0) for the full changelog, and check out the [Dewey documentation](/docs/projects/dewey/) for the complete feature reference. diff --git a/content/blog/dewey-slash-command-ux.md b/content/blog/dewey-slash-command-ux.md new file mode 100644 index 0000000..46e90fc --- /dev/null +++ b/content/blog/dewey-slash-command-ux.md @@ -0,0 +1,184 @@ +--- +title: "Zero-Code UX — How a Markdown File Became Dewey's Best Feature" +description: "The most impactful feature in Dewey v3.1.0 is a markdown file, not a Go package. The /dewey-store slash command teaches AI agents three interaction patterns for knowledge capture — without changing a single line of code." +lead: "The most impactful UX improvement in an agent ecosystem can be a markdown file — not a Go package. /dewey-store teaches agents three knowledge capture patterns without writing code." +slug: "dewey-slash-command-ux" +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 104 +toc: true +categories: ["Engineering"] +tags: ["dewey", "slash-commands", "developer-experience", "UX"] +contributors: ["Unbound Force"] +--- + +## The Problem Nobody Talks About + +Developer tools optimize for the power user who already knows the flags. Documentation lists every parameter, every option, every edge case — and assumes the reader arrives with a mental model of how the tool works. But the most common interaction with Dewey's `store_learning` tool looks nothing like a power user session. + +The real scenario: a developer finishes a 45-minute architecture discussion in Slack. The thread contains three decisions, a rejected alternative, and a gotcha about rate limiting. The developer knows this knowledge should be captured. They open their agent, paste the thread, and type something like "store this." + +What happens next is the problem. The agent calls `store_learning` with a vague tag like "architecture" and a category of "context." Forty-five minutes of nuanced discussion collapses into a single learning with a generic label. The knowledge is stored, but it's unfindable — buried under a tag so broad it matches hundreds of other entries. The developer needed guided extraction, not a raw API call. + +## A Markdown File, Not a Go Package + +Dewey v3.1.0 shipped the `/dewey-store` slash command. The implementation is a markdown instruction file — zero lines of Go changed, no new endpoints, no schema migrations. The file teaches AI agents three progressive interaction patterns for knowledge capture, each matching a different level of user intent. + +This is the core insight: in an agent ecosystem, UX improvements don't require code changes. They require better instructions. The agent already has access to `store_learning`. What it lacked was a structured protocol for deciding *how* to use it based on what the user provides. + +The slash command file acts as a decision tree. When a user invokes `/dewey-store`, the agent reads the instruction file and selects one of three modes based on the input it receives. The user never sees the mode selection — they experience a conversation that adapts to their needs. + +## Three Modes for Three Intentions + +### Mode 1: Fully Specified + +Power users who know their tag taxonomy and category system can bypass all guidance. They provide everything upfront, and the agent executes without negotiation. + +``` +/dewey-store --tag auth-design --category decision + +We decided to use short-lived JWTs with a 15-minute expiry +and opaque refresh tokens stored server-side. RSA256 signing +with key rotation every 90 days. +``` + +The agent calls `store_learning` with the exact tag and category provided. No suggestions, no confirmation prompts, no friction. This mode exists because experienced users should never be slowed down by guardrails designed for newcomers. + +### Mode 2: Suggested + +The most common mode. The user provides content but no metadata. The agent analyzes the content and proposes tags ranked by specificity, plus a category based on content patterns. + +``` +/dewey-store + +We tried using WebSockets for the real-time dashboard but +hit connection limit issues behind our load balancer. Switched +to SSE (Server-Sent Events) which works through HTTP/2 without +special proxy configuration. Latency increased by ~200ms but +operational complexity dropped significantly. +``` + +The agent responds with ranked suggestions: + +``` +Proposed tag (ranked by specificity): + 1. sse-migration — matches the specific technology switch + 2. real-time-dashboard — matches the feature context + 3. infrastructure — broad fallback + +Proposed category: decision +Rationale: content describes evaluating alternatives and selecting +an approach with trade-off analysis. + +Store with these? [Y/adjust/cancel] +``` + +The ranking by specificity matters. Generic tags like "infrastructure" appear last because they produce the least findable results. The agent nudges toward precise tags without forcing them — the user can accept, adjust, or override. + +### Mode 3: Extract + +The highest-value mode for meeting transcripts, Slack threads, and design discussions. The user pastes a long conversation, and the agent breaks it into multiple distinct learnings, each with its own tag and category proposal. + +``` +/dewey-store --extract + +[Pasted Slack thread about authentication redesign, 47 messages] +``` + +The agent identifies distinct knowledge units and presents them individually: + +``` +Extracted 4 learnings from this thread: + +Learning 1/4: + Content: "JWT refresh tokens must be opaque (not JWT themselves) + to allow server-side revocation without maintaining a blocklist + of signed tokens." + Tag: jwt-refresh-design + Category: decision + [Store / Edit / Skip] + +Learning 2/4: + Content: "Auth0 rate-limits token refresh to 30 requests per + minute per user. Batch operations that trigger multiple refreshes + need a token cache layer." + Tag: auth0-rate-limits + Category: gotcha + [Store / Edit / Skip] + +Learning 3/4: + Content: "Session duration was set to 8 hours based on the + average developer workday. Shorter sessions (1-2 hours) caused + excessive re-authentication during long debugging sessions." + Tag: session-duration + Category: context + [Store / Edit / Skip] + +Learning 4/4: + Content: "The team rejected PASETO tokens in favor of JWT + because PASETO's Go library lacks FIPS 140-2 compliance, + which is required for FedRAMP authorization." + Tag: paseto-rejection + Category: decision + [Store / Edit / Skip] +``` + +Each learning gets individual review. The user can store all four, edit specific ones, or skip learnings that aren't worth preserving. A 47-message Slack thread becomes four precise, tagged, findable knowledge entries — each with a category that reflects its nature. + +## Before and After + +**Before `/dewey-store`**: The developer pastes a Slack thread and says "remember this." The agent calls `store_learning` once with `tag: "auth"` and `category: "context"`. One monolithic entry. Unfindable in six months. + +```go +// What the agent did before +store_learning({ + information: "[entire 47-message Slack thread pasted verbatim]", + tag: "auth", + category: "context" +}) +// Result: 1 learning, generic tag, wrong category for 3 of 4 insights +``` + +**After `/dewey-store`**: The same thread produces four distinct learnings. Each has a specific tag that matches its content. Each has a category that reflects whether it's a decision, a gotcha, or background context. Each is individually reviewable before storage. + +```go +// What the agent does now +store_learning({ + information: "JWT refresh tokens must be opaque...", + tag: "jwt-refresh-design", + category: "decision" +}) +store_learning({ + information: "Auth0 rate-limits token refresh to 30/min...", + tag: "auth0-rate-limits", + category: "gotcha" +}) +// ... 2 more, each reviewed and approved by the user +// Result: 4 learnings, specific tags, accurate categories +``` + +The difference isn't in the agent's capabilities — `store_learning` accepted tags and categories before the slash command existed. The difference is in the interaction design. The agent now follows a structured protocol that guides the user through metadata selection instead of guessing on their behalf. + +## Why This Matters Beyond Dewey + +Slash commands as markdown instruction files represent a pattern that applies to any agent-augmented tool. The pattern has three properties worth noting. + +**Zero deployment cost.** A markdown file ships with the project. No build step, no versioning headaches, no API compatibility concerns. The instruction file can be updated independently of the tool it teaches agents to use. + +**Progressive disclosure.** The three modes — fully specified, suggested, extract — match the user's level of intent. Power users skip the guidance. New users get suggestions. Users with bulk content get extraction. The same entry point serves all three without branching the UI. + +**Composability.** The slash command doesn't replace `store_learning` — it wraps it with interaction design. The underlying tool remains a stable API. The instruction file adds a UX layer that can evolve independently. New modes can be added (batch import from files, periodic review of stored learnings) without changing the tool's contract. + +This is the leverage point in agent ecosystems: the gap between a tool's API and a user's intent is bridged by instructions, not code. Every tool in your stack has this gap. Slash commands are one way to close it — with a markdown file and zero deploys. + +## Get Started + +The `/dewey-store` slash command shipped in [Dewey v3.1.0](https://github.com/unbound-force/dewey). To use it: + +1. Update Dewey to v3.1.0 or later +2. Invoke `/dewey-store` in any agent session with Dewey MCP tools configured +3. Paste content — the agent selects the appropriate mode based on your input + +To build your own slash commands for other tools, examine the `/dewey-store` instruction file as a template. The pattern — mode selection based on input analysis, ranked suggestions, and per-item review — transfers to any `store` or `create` operation where metadata selection is the friction point. + +Read the [Dewey documentation](/docs/projects/dewey/) for the full tool reference, or explore the [source on GitHub](https://github.com/unbound-force/dewey) to see how the instruction file integrates with the MCP tool surface. diff --git a/content/blog/gaze-baseline-comparison.md b/content/blog/gaze-baseline-comparison.md new file mode 100644 index 0000000..c252eee --- /dev/null +++ b/content/blog/gaze-baseline-comparison.md @@ -0,0 +1,155 @@ +--- +title: "Gaze Baseline Comparison — Per-Function CRAP Regression Detection" +description: "Gaze now detects per-function CRAP score regressions by comparing against a baseline file. Zero configuration beyond creating the initial baseline — auto-detection handles the rest." +lead: "From external scripts to native regression detection. gaze crap auto-detects a baseline file and classifies every function as regression, improvement, new, or removed — one exit code gates your CI." +slug: "gaze-baseline-comparison" +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 106 +toc: true +categories: ["Engineering"] +tags: ["gaze", "CRAP", "baseline", "CI", "testing"] +contributors: ["Unbound Force"] +--- + +## The 850-Line Comparison Script Problem + +Organizations adopting Gaze for CRAP score analysis faced a gap: Gaze could compute per-function CRAP scores for a single run, but it had no way to compare those scores against a previous baseline. Detecting regressions — a function whose complexity increased or whose coverage dropped — required external tooling. The only option was org-infra's reusable GitHub Actions workflow, which embedded an 850-line bash/Python comparison script to diff two JSON reports and flag regressions. + +That script worked, but it created a hard dependency on org-infra for every repository that wanted regression detection. Teams that couldn't use the reusable workflow had to rebuild the comparison logic from scratch. The result was fragmented implementations, inconsistent thresholds, and no local development story — engineers couldn't check for regressions before pushing to CI. + +## Convention Over Configuration + +Gaze now handles baseline comparison natively. The design follows a convention-over-configuration principle: create a `.gaze/baseline.json` file in your repository, and `gaze crap` auto-detects it on the next run. No flags, no config files, no environment variables. The baseline file is the configuration. + +Generating the initial baseline is a single command: + +```bash +gaze crap --json > .gaze/baseline.json +``` + +Commit that file to your repository. On subsequent runs, `gaze crap` detects `.gaze/baseline.json`, loads it, and compares every function in the current run against the baseline. Each function receives a classification: + +- **regression** — CRAP score increased beyond the epsilon tolerance +- **improvement** — CRAP score decreased beyond the epsilon tolerance +- **new** — function exists in the current run but not in the baseline +- **removed** — function exists in the baseline but not in the current run + +If any function is classified as a regression, `gaze crap` exits with code 1. No regressions means exit code 0. One exit code gates your entire CI pipeline. + +## Example Output + +When `gaze crap` detects a baseline, the output includes a comparison section after the standard CRAP table: + +```text +CRAP Score Analysis +=================== + + Function Complexity Coverage CRAP + ──────────────────────────────── ────────── ──────── ──── + parseConfig 12 85.0% 14 + validateInput 8 92.0% 9 + handleRequest 15 40.0% 48 + formatOutput 3 100.0% 3 + processBatch (new) 6 78.0% 8 + +Baseline Comparison (.gaze/baseline.json) +========================================= + + Function Baseline Current Delta Status + ────────────── ──────── ─────── ────── ─────────── + handleRequest 32 48 +16.0 REGRESSION + parseConfig 18 14 -4.0 improvement + validateInput 9 9 0.0 unchanged + formatOutput 3 3 0.0 unchanged + processBatch — 8 — new + legacyParser 22 — — removed + +Summary: 1 regression, 1 improvement, 1 new, 1 removed +Exit code: 1 (regression detected) +``` + +The `handleRequest` function regressed from CRAP 32 to CRAP 48 — its complexity increased while coverage dropped. That single regression triggers exit code 1, blocking the pipeline until the author addresses it. + +## Configurable Tolerance + +Two thresholds control how Gaze classifies functions during comparison. Both have sensible defaults that work without configuration, and both accept overrides for teams with specific requirements. + +**Epsilon (default: 0.5)** absorbs platform noise. CRAP scores can fluctuate by small amounts across operating systems, Go versions, or test execution order. An epsilon of 0.5 means a function must change by more than 0.5 CRAP points to be classified as a regression or improvement. Scores that shift within the epsilon band are classified as unchanged. + +```bash +# Tighten epsilon for high-precision environments +gaze crap --epsilon 0.1 + +# Loosen epsilon for projects with known platform variance +gaze crap --epsilon 1.0 +``` + +**New-function threshold (default: 30)** enforces standards on new code. A function that appears for the first time with a CRAP score above 30 is classified as a regression, not as "new." This prevents authors from introducing high-complexity, low-coverage functions and bypassing the baseline gate because the function has no prior score to regress from. + +```bash +# Enforce a stricter threshold for new functions +gaze crap --new-threshold 20 +``` + +## CI Integration + +Baseline comparison works identically in CI and local development. The same command, the same exit code, the same output. A GitHub Actions workflow that gates on CRAP regressions requires no special configuration beyond ensuring the baseline file is committed: + +```yaml +name: Quality Gate +on: [pull_request] + +jobs: + crap-check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version: "1.23" + + - name: Install Gaze + run: go install github.com/unbound-force/gaze/cmd/gaze@latest + + - name: Run tests with coverage + run: go test -coverprofile=coverage.out ./... + + - name: CRAP baseline check + run: gaze crap + # Exit code 1 if any function regressed. + # .gaze/baseline.json is auto-detected from the repo. +``` + +No wrapper scripts. No reusable workflow dependency. No post-processing step to parse JSON and decide pass/fail. The `gaze crap` command is the entire gate. + +To update the baseline after intentional changes (refactoring that temporarily increases a score, or accepting a justified complexity increase), regenerate and commit: + +```bash +gaze crap --json > .gaze/baseline.json +git add .gaze/baseline.json +git commit -m "chore: update CRAP baseline" +``` + +## Constitution Alignment + +This feature directly fulfills Principle III (Actionable Output) from the Unbound Force constitution. Principle III requires that tool output be comparable across runs — a single-run CRAP report is informative, but it cannot answer the question "did this change make things worse?" without a reference point. Baseline comparison closes that gap by making cross-run comparability a native capability rather than an external integration concern. + +The classification model (regression, improvement, new, removed) also satisfies the actionability requirement. Each classification maps to a concrete action: regressions must be fixed, improvements validate refactoring effort, new functions are evaluated against the threshold, and removed functions confirm cleanup. No classification leaves the engineer wondering "what do I do with this information?" + +## Try It + +Set up baseline comparison in your own repository with the companion tutorial: [Setting Up CRAP Baseline Comparison in CI](/docs/tutorials/gaze-crap-baseline-ci/). The tutorial walks through generating the initial baseline, configuring thresholds for your project, and integrating the gate into an existing GitHub Actions workflow. + +Install Gaze and generate your first baseline: + +```bash +go install github.com/unbound-force/gaze/cmd/gaze@latest +go test -coverprofile=coverage.out ./... +gaze crap --json > .gaze/baseline.json +git add .gaze/baseline.json +git commit -m "chore: add CRAP baseline" +``` + +From that point forward, every `gaze crap` run compares against the baseline and exits non-zero on regression. No configuration files to maintain, no external scripts to keep in sync, no CI-specific behavior that diverges from local development. diff --git a/content/blog/multi-platform-support.md b/content/blog/multi-platform-support.md new file mode 100644 index 0000000..cfc424f --- /dev/null +++ b/content/blog/multi-platform-support.md @@ -0,0 +1,101 @@ +--- +title: "Multi-Platform Support — uf init Now Scaffolds for Cursor" +description: "Unbound Force gains multi-platform scaffold support. uf init --platform cursor generates native Cursor configuration alongside or instead of OpenCode files — from a single canonical asset set." +lead: "From OpenCode-only to platform-agnostic. uf init --platform cursor translates convention packs into .mdc rules and MCP config into .cursor/mcp.json — one command, two platforms." +slug: "multi-platform-support" +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 109 +toc: true +categories: ["Engineering"] +tags: ["multi-platform", "cursor", "opencode", "scaffolding"] +contributors: ["Unbound Force"] +--- + +## The Single-Platform Ceiling + +Until now, Unbound Force was an OpenCode integration. Convention packs, MCP server configuration, agent prompts, and skill definitions all targeted one platform's file layout. If your team used Cursor, you were out of luck — or stuck maintaining a parallel set of hand-written configuration files that drifted from the canonical source within days. + +This constraint was artificial. The *knowledge* encoded in convention packs — coding standards, architectural patterns, review severity definitions — has nothing to do with which editor runs the AI agent. A rule like "exported Go functions require GoDoc comments" is equally valid whether the agent reads it from `.opencode/uf/packs/go.md` or from a Cursor `.mdc` rule file. The platform-specific part is the container format, not the content. + +Spec 035 eliminates this ceiling. `uf init --platform cursor` now generates native Cursor configuration from the same canonical asset set that powers OpenCode scaffolding. + +## One Asset Set, Multiple Outputs + +The core design follows the Strategy pattern. A `Platform` interface defines the contract for translating canonical assets into platform-specific files. Each platform implementation — `OpenCodePlatform`, `CursorPlatform`, and future additions — handles its own file layout, naming conventions, and format requirements. + +```go +type Platform interface { + Name() string + Scaffold(ctx context.Context, assets AssetSet, opts Options) error +} +``` + +Convention packs are the clearest example of this translation. In OpenCode, a convention pack is a Markdown file at `.opencode/uf/packs/go.md` that agents read during code review. In Cursor, the equivalent is an `.mdc` rule file with YAML frontmatter specifying glob patterns for auto-attachment. The content — the actual coding rules — stays identical. The scaffold engine handles the format translation. + +```yaml +# .cursor/rules/go.mdc (generated) +--- +description: "Go convention pack — coding standards for Go source files" +globs: ["**/*.go"] +alwaysApply: false +--- + +[CS-001] Exported functions MUST have GoDoc comments... +``` + +MCP server configuration follows the same principle. OpenCode stores MCP config in `opencode.json` under the `mcpServers` key. Cursor expects it in `.cursor/mcp.json` with a slightly different schema. The scaffold engine reads the canonical MCP server definitions and writes the correct format for each target platform. + +## Dual-Platform Projects + +Teams that use both OpenCode and Cursor — or that are migrating between them — can scaffold for multiple platforms in a single command: + +```bash +uf init --platform opencode --platform cursor +``` + +This generates both `.opencode/` and `.cursor/` directory trees from the same source assets. The two configurations coexist in the same repository without conflict. Each developer uses whichever platform they prefer, and both see the same convention packs, the same MCP servers, and the same agent capabilities. + +This matters for adoption. Teams do not switch tools overnight. A migration path that lets both platforms run side-by-side, drawing from a single source of truth, removes the "all or nothing" barrier that blocks tool adoption in larger organizations. + +## Backward Compatibility + +Existing `uf init` behavior is unchanged. Without an explicit `--platform` flag, the command defaults to OpenCode — the same output it has always produced. No existing workflows break. No configuration files move. The multi-platform capability is additive. + +Projects that have already run `uf init` can add Cursor support incrementally: + +```bash +uf init --platform cursor +``` + +This generates the Cursor-specific files without touching the existing OpenCode configuration. The scaffold engine detects what already exists and fills in the gaps rather than overwriting. + +## Extensibility: The Platform Interface + +The `Platform` interface is deliberately minimal. Adding support for a new AI coding tool — Claude Code, GitHub Copilot, or whatever ships next quarter — requires implementing a single interface with a handful of methods. The canonical asset set does not change. The translation logic is isolated in the new platform implementation. + +This design decision reflects a bet about the market: AI coding tools will proliferate, and teams will use more than one. Building Unbound Force around a platform-agnostic asset model means the project's value compounds with each new platform rather than fragmenting across incompatible configurations. + +The `Platform` interface also opens the door for community contributions. A team using an internal or niche AI tool can implement the interface for their platform without modifying the core scaffold engine. + +## What This Means for the Project + +This release transforms Unbound Force from a single-tool integration into a platform-agnostic agent framework. Convention packs, MCP servers, agent prompts, and skills are now portable assets that target any supported platform through a clean translation layer. + +The architectural significance goes beyond Cursor support. By separating *what* the agents know (convention packs, specs, constitutions) from *where* they run (OpenCode, Cursor, future platforms), Unbound Force becomes the canonical source of engineering standards for a team — regardless of which AI coding tool individual developers prefer. + +## Get Started + +Update to the latest `uf` binary and scaffold for Cursor: + +```bash +uf init --platform cursor +``` + +For dual-platform projects: + +```bash +uf init --platform opencode --platform cursor +``` + +Review the generated `.cursor/rules/` directory to see your convention packs translated into `.mdc` format, and `.cursor/mcp.json` for your MCP server configuration. File an issue on the [unbound-force/unbound-force](https://github.com/unbound-force/unbound-force) repository if you hit edge cases in the translation — the platform interface is new, and real-world feedback sharpens it. diff --git a/content/blog/pluggable-llm-providers.md b/content/blog/pluggable-llm-providers.md new file mode 100644 index 0000000..108869b --- /dev/null +++ b/content/blog/pluggable-llm-providers.md @@ -0,0 +1,153 @@ +--- +title: "Dewey Goes Cloud-Optional — Pluggable LLM Providers for Embedding and Synthesis" +description: "Dewey's new pluggable provider architecture lets teams choose between local Ollama and cloud Vertex AI for both embedding and synthesis — or mix them. Local-first, cloud-optional." +lead: "Local LLMs produce lower-quality synthesis and require GPU hardware. Dewey's pluggable providers let you mix local Ollama embeddings with cloud Vertex AI synthesis — or go fully local. Your choice." +slug: "pluggable-llm-providers" +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 105 +toc: true +categories: ["Engineering"] +tags: ["dewey", "LLM", "providers", "vertex-ai", "ollama"] +contributors: ["Unbound Force"] +--- + +## The Problem with Local-Only + +Dewey started as a local-first knowledge system. Ollama handled both embedding and synthesis, which meant zero cloud dependencies and full data sovereignty. That design worked — until it didn't. + +Local LLMs produce measurably lower-quality synthesis than cloud models. Knowledge compilation — where Dewey groups learnings by topic, resolves contradictions, and produces current-state articles — demands reasoning that smaller local models struggle with. The output reads like a summary, not a synthesis. Teams without dedicated GPU hardware hit a second wall: Ollama's embedding models run slowly on CPU, making semantic search across large vaults impractical. + +The original architecture forced an all-or-nothing choice. You ran everything locally, or you didn't run Dewey at all. That constraint needed to break. + +## Pluggable Provider Interfaces + +The `016-pluggable-providers` branch introduces two provider interfaces — `Embedder` and `Synthesizer` — that decouple Dewey's intelligence layer from any specific LLM backend. Each interface has exactly one job: `Embedder` converts text into vector embeddings for semantic search, and `Synthesizer` generates natural language output for knowledge compilation. + +Factory functions `NewEmbedderFromConfig()` and `NewSynthesizerFromConfig()` centralize provider construction. They read the configuration, select the correct backend, and return a ready-to-use provider. Callers never import provider-specific packages directly. Adding a new backend — Anthropic, OpenAI, a future local model — means implementing the interface and registering it in the factory. No call sites change. + +```go +// Factory selects the provider based on config. +embedder, err := providers.NewEmbedderFromConfig(cfg) +synthesizer, err := providers.NewSynthesizerFromConfig(cfg) +``` + +Ollama remains the zero-config default. If you install Dewey and do nothing else, it behaves exactly as before — local Ollama for both embedding and synthesis. No API keys, no cloud accounts, no configuration files required. + +## Configuration: Two New Fields + +Two new fields in Dewey's configuration control provider selection: `embedding.provider` and `synthesis.provider`. Each accepts `ollama` or `vertex-ai` as values. + +```yaml +# Per-vault config: .dewey/config.yaml +embedding: + provider: ollama + model: nomic-embed-text + +synthesis: + provider: vertex-ai + model: gemini-2.5-flash + project: my-gcp-project + location: us-central1 +``` + +For teams running multiple vaults, a global configuration file at `~/.config/dewey/config.yaml` sets defaults that individual vaults can override. This prevents duplicating Vertex AI credentials across every project. The vault-level config takes precedence when both exist. + +```yaml +# Global config: ~/.config/dewey/config.yaml +synthesis: + provider: vertex-ai + model: gemini-2.5-flash + project: my-gcp-project + location: us-central1 +``` + +### Config Precedence: A Deliberate Asymmetry + +Embedding and synthesis handle environment variables differently, and this is intentional. For embedding, environment variables like `DEWEY_EMBEDDING_PROVIDER` override the config file. This preserves backward compatibility — existing CI pipelines and scripts that set environment variables continue to work without modification. + +For synthesis, the relationship is inverted: the config file takes precedence, and environment variables serve as a fallback. Synthesis configuration is a deliberate architectural choice that teams make once and commit to version control. Letting a stray environment variable silently swap your synthesis backend would undermine that intentionality. The asymmetry reflects different usage patterns: embedding config is often set dynamically in automation, while synthesis config is a stable team decision. + +## Vertex AI: Pure Go, No CGO + +The Vertex AI provider authenticates through `golang.org/x/oauth2/google`, which uses Application Default Credentials (ADC). Run `gcloud auth application-default login` once, and Dewey picks up the credentials automatically. No API keys to manage, no secrets to rotate, no CGO dependencies to cross-compile around. + +This matters for distribution. Dewey ships as a single static binary. CGO dependencies would force platform-specific builds, complicate `go install`, and break the "download and run" experience. The pure Go constraint was non-negotiable during design. + +```bash +# One-time setup for Vertex AI +gcloud auth application-default login +``` + +## The Recommended Setup: Hybrid Providers + +The architecture supports mixing providers — and the hybrid configuration is the recommended setup for most teams. Run Ollama locally for embeddings and route synthesis to Vertex AI. + +```yaml +embedding: + provider: ollama + model: nomic-embed-text + +synthesis: + provider: vertex-ai + model: gemini-2.5-flash + project: my-gcp-project + location: us-central1 +``` + +This combination plays to each provider's strengths. Ollama's `nomic-embed-text` produces high-quality embeddings with low latency on commodity hardware — no GPU required for the embedding model. Vertex AI's Gemini models handle the heavy reasoning that knowledge compilation demands. Your raw data stays local for indexing and search; only the synthesis prompts (which contain aggregated, anonymized learnings) leave the machine. + +Teams that need full data sovereignty can set both providers to `ollama` and accept the synthesis quality trade-off. Teams that want maximum quality can set both to `vertex-ai`. The pluggable architecture makes this a configuration decision, not a code change. + +## Closing the Compilation Loop: `store_compiled` + +The new `store_compiled` MCP tool completes the agent-driven compilation workflow. Previously, Dewey's `compile` tool returned synthesis prompts that an agent would process, but there was no way to persist the result back into the knowledge graph. The compiled article existed only in the conversation context. + +With `store_compiled`, the workflow becomes a closed loop: + +1. Agent calls `dewey_compile` — Dewey groups learnings by topic and returns synthesis prompts +2. Agent performs synthesis (using whatever LLM powers the agent) +3. Agent calls `dewey_store_compiled` with the synthesized article, source learnings, and topic tag +4. Dewey persists the compiled article with full provenance metadata + +``` +compile → synthesize → store_compiled → searchable knowledge +``` + +This means compiled knowledge articles are now first-class citizens in the graph. They appear in semantic search results, carry provenance tracking (which learnings were compiled, which model performed synthesis), and can be promoted from draft to validated status through the existing `dewey_promote` workflow. + +## Constitution Amendment: Local by Default, Cloud Opt-In + +This change required amending Dewey's constitution. The original "Local-Only Processing" principle stated that all data processing must happen on the user's machine. That principle served its purpose — it forced the architecture to work without cloud dependencies — but it also prevented teams from opting into cloud services when the trade-off made sense. + +The amended principle reads "Local by Default, Cloud Opt-In." Dewey works out of the box with no cloud services. Cloud providers are available for teams that choose them, with explicit configuration required. No data leaves the machine unless the user configures a cloud provider. The amendment preserves the original intent (privacy, zero-config startup) while removing the artificial ceiling on quality. + +Constitutional amendments in the Unbound Force ecosystem are not taken lightly. They require explicit justification, documented trade-offs, and alignment with the broader governance model. This amendment passed because it expanded user choice without reducing the default privacy guarantees. + +## Get Started + +Upgrade to the latest Dewey build from the `016-pluggable-providers` branch: + +```bash +go install github.com/unbound-force/dewey/cmd/dewey@latest +``` + +To add Vertex AI synthesis to an existing vault: + +```bash +# Authenticate with GCP +gcloud auth application-default login + +# Add synthesis config to your vault +cat >> .dewey/config.yaml << 'EOF' +synthesis: + provider: vertex-ai + model: gemini-2.5-flash + project: YOUR_PROJECT + location: us-central1 +EOF +``` + +Run `dewey_compile` through your MCP client to test the synthesis quality difference. Compare the output against a pure Ollama compilation of the same learnings. The difference in reasoning depth is the reason this architecture exists. + +For questions, issues, or provider requests, open an issue on the [Dewey repository](https://github.com/unbound-force/dewey). diff --git a/content/blog/prompt-hardening.md b/content/blog/prompt-hardening.md new file mode 100644 index 0000000..201e72e --- /dev/null +++ b/content/blog/prompt-hardening.md @@ -0,0 +1,178 @@ +--- +title: "Prompt Hardening for Compression Resilience — Engineering Agent Prompts That Survive DCP" +description: "When LLM context windows fill up, compressors summarize agent prompts. Critical constraints get dropped, causing silent quality gate bypasses. Six PRs systematically hardened all embedded prompts against Dynamic Context Protocol compression." +lead: "Your agent's instructions are being silently compressed. Critical constraints get dropped, quality gates get bypassed, and nobody notices. Here is how we engineered prompts that survive." +slug: "prompt-hardening" +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 108 +toc: true +categories: ["Engineering"] +tags: ["prompt-engineering", "DCP", "compression", "reliability"] +contributors: ["Unbound Force"] +--- + +## The Silent Failure Mode Nobody Talks About + +AI agent systems run on prompts — long, detailed instructions that define behavior, enforce constraints, and gate quality. These prompts work flawlessly in short sessions. But as context windows fill up during complex tasks, something happens that most teams never notice: the LLM's context compressor kicks in and *summarizes your instructions*. + +Dynamic Context Protocol (DCP) compression is a practical necessity. Context windows are finite, and when a multi-step workflow generates thousands of tokens of tool output, conversation history, and intermediate reasoning, older content gets compressed to make room. The problem is that "older content" includes your agent's system prompt — the document that tells it what rules to follow, what gates to enforce, and what behaviors are forbidden. + +When a compressor summarizes "NEVER reserve files you don't intend to edit" into "manage file reservations appropriately," the constraint evaporates. The agent starts reserving files speculatively. Nobody gets an error. The behavior change is silent. You discover it three days later when a parallel worker deadlocks on a reservation that should never have existed. + +## Four Fragility Patterns + +We audited every embedded prompt across the Unbound Force agent swarm — coordinator prompts, worker prompts, skill instructions, command templates — and identified four structural patterns that make constraints fragile under compression. + +### 1. Constraints in Trailing Sections + +Compressors operate with a positional bias: opening content survives at higher rates than closing content. Constraints placed at the end of a prompt — after workflow steps, after examples, after the "main" instructions — are the first candidates for summarization or outright removal. A "Behavioral Constraints" section at the bottom of a 2,000-token prompt has a measurably lower survival rate than the same constraints placed in the first 200 tokens. + +### 2. Implicit Ordering via Numbered Lists + +Numbered lists suggest sequence, but compressors treat them as enumerable items that can be merged. A five-step workflow like "1. Reserve files, 2. Read existing code, 3. Implement changes, 4. Run tests, 5. Complete task" gets compressed into "Reserve files, implement changes, and complete the task." Steps 2 and 4 — reading context and running tests — vanish because the compressor treats them as elaboration on the core action. + +### 3. Safety Rules in Mid-List Positions + +Research on LLM attention patterns shows a "lost in the middle" effect: items at the start and end of a list receive more attention than items in the middle. Compressors exhibit the same bias. A safety constraint at position 4 of 7 in a bulleted list has the lowest survival rate of any position. If your "do not force-push" rule sits between "use conventional commits" and "write descriptive PR titles," it is the most likely to be dropped. + +### 4. Parallel Do/Don't Lists + +A common prompt pattern presents a "Do" list and a "Don't" list side by side. Under compression, these lists get summarized independently. The "Do" list compresses to its most prominent actions. The "Don't" list compresses to its most prominent prohibitions. The subtle interplay between them — "Do X *but* don't do Y *while* doing X" — collapses into two disconnected summaries that lose the conditional relationship. + +## Six Hardening Techniques + +Each fragility pattern has a corresponding structural defense. These techniques are not stylistic preferences — they are engineering decisions backed by observed compression behavior. + +### Identity-First Opening with Embedded Constraints + +Compressors preserve opening sentences at the highest rate. The first paragraph of a prompt is treated as the "topic sentence" that anchors all subsequent summarization. By embedding critical constraints directly into the identity statement, they inherit the positional survival advantage. + +```markdown +# Before (fragile) +You are a code review agent. Review code for quality issues. + +...200 lines of workflow... + +## Constraints +- Never approve code that fails tests. +``` + +```markdown +# After (hardened) +You are the Quality Gate agent. You MUST NOT approve any code +that fails tests. You enforce quality through structured review. +``` + +The constraint "MUST NOT approve code that fails tests" now lives in the opening sentence. A compressor summarizing this prompt retains the identity and its embedded constraint as the anchor for the summary. + +### Dedicated Critical Constraints Section (Early Position) + +Constraints that govern safety, correctness, or gate integrity get their own section placed *before* the workflow — not after it. This exploits positional bias: the compressor reaches the constraints before it reaches the workflow steps, and treats them as higher-priority content. + +```markdown +## Critical Constraints + +- **File Reservation**: MUST reserve files BEFORE editing. MUST release after completion. +- **Review Gate**: MUST NOT call complete() without prior review approval. +- **No Force Push**: NEVER force-push to shared branches. + +## Workflow + +FIRST, reserve the files you will modify... +``` + +### RFC 2119 Keywords as Compression Signals + +The keywords MUST, MUST NOT, SHALL, SHALL NOT, SHOULD, SHOULD NOT, MAY, REQUIRED, and RECOMMENDED carry semantic weight that compressors recognize. An uppercase MUST signals a non-negotiable requirement. A lowercase "should" signals a preference that can be dropped under space pressure. + +This is not about shouting. It is about giving the compressor a machine-readable importance signal. When space is limited and the compressor must choose between retaining "MUST run tests before completing" and "should add helpful comments," the RFC 2119 keyword tips the decision toward retaining the constraint. + +### Decision Tables Replacing Parallel Lists + +Parallel do/don't lists compress independently and lose their relational structure. A decision table encodes the same information as a single coherent unit that compressors treat atomically. + +```markdown +# Before (fragile parallel lists) +## Do +- Reserve files before editing +- Run tests after changes + +## Don't +- Reserve files you won't edit +- Skip tests for "small" changes +``` + +```markdown +# After (hardened decision table) +| Situation | Action | Rationale | +|---|---|---| +| Before editing a file | Reserve ONLY that file | Prevents speculative locks | +| After any code change | Run full test suite | No change is "too small" to test | +| File editing complete | Release reservation | Prevents worker deadlocks | +``` + +The table survives as a unit. A compressor summarizing it retains the situation-action pairing rather than splitting actions from their conditions. + +### Inline Parameters at Point-of-Use + +Configuration values (timeouts, thresholds, retry counts) placed in a separate "Configuration" section get dropped when that section is compressed away. The same values placed inline — at the exact point where the action occurs — survive with their parent action. + +```markdown +# Before (fragile) +## Workflow +1. Report progress at milestones. + +## Configuration +- Progress milestones: 25%, 50%, 75% +- Max retries: 3 +``` + +```markdown +# After (hardened) +## Workflow +FIRST, report progress at 25%, 50%, and 75% milestones (max 3 retries per report). +``` + +### Temporal Ordering Markers + +Bare numbered lists lose their sequence under compression. Explicit temporal markers — FIRST, THEN, NEXT, AFTER, FINALLY — encode ordering as semantic content rather than structural formatting. A compressor that merges list items still retains "FIRST reserve files, THEN implement changes, FINALLY run tests" because the ordering words are part of the content, not the formatting. + +### Redundant Constraint Placement (Defense-in-Depth) + +For the highest-severity constraints — the ones where a single violation causes data loss, deadlocks, or silent quality gate bypasses — redundancy is the final defense. Place the constraint in the identity opening, in the Critical Constraints section, and inline at the point of action. If compression removes two of the three instances, one survives. + +This violates DRY. That is intentional. DRY optimizes for human maintainability. Agent prompts optimize for machine reliability under degraded conditions. The trade-off is explicit: three copies of "MUST NOT force-push" cost 15 extra tokens but prevent a catastrophic failure mode. + +## The Engineering Process + +Each prompt hardening was not a quick find-and-replace. Every prompt went through a full OpenSpec workflow: proposal, design document, specification, task breakdown, implementation, and structural tests. Six pull requests landed across the replicator repository (PRs #54 through #59), each targeting a specific prompt scope: + +1. **Coordinator prompt** (PR #54) — The orchestration layer that manages worker lifecycle +2. **Forge command prompt** (PR #55) — The swarm decomposition and dispatch logic +3. **Forge-coordination skill** (PR #56) — The skill injected into coordinators for multi-worker management +4. **Worker prompt** (PR #57) — The template given to every spawned worker agent +5. **Handoff command prompt** (PR #58) — The session handoff and context transfer logic +6. **Forge-global and always-on-guidance skills** (PR #59) — Cross-cutting skills loaded into every agent session + +Each PR included structural tests that verify compression-resilience properties: critical constraints appear in the first N tokens, RFC 2119 keywords are present on safety rules, decision tables replace parallel lists, and temporal markers are present on sequential workflows. These tests catch regressions — if a future edit moves a constraint to a trailing section, the test fails. + +## The Trade-Offs We Accepted + +Hardened prompts are longer. The coordinator prompt grew by approximately 20% in token count. Every redundant constraint placement, every inline parameter, every temporal marker adds tokens. In a system where context window budget matters, this is a real cost. + +Hardened prompts are less scannable for humans. The identity-first opening packs constraints into dense paragraphs instead of clean bulleted lists. Decision tables are harder to skim than parallel do/don't lists. A developer reading the prompt for the first time needs more effort to parse the structure. + +Hardened prompts intentionally violate DRY. The same constraint appears in multiple locations within the same document. A maintainer updating the constraint must update it in every location or risk inconsistency. + +We accepted all three trade-offs because these prompts are not documentation for humans. They are executable specifications for machines operating under adversarial conditions. The "adversary" is not a malicious actor — it is a well-intentioned compressor doing its job of freeing context window space. Reliability under compression outweighs aesthetics, scannability, and maintenance convenience. + +## What This Means for Your Agent Systems + +If you are building AI agent systems with long-running sessions, multi-step workflows, or tool-heavy interactions, your prompts are being compressed. The question is not *whether* compression happens but *whether your constraints survive it*. + +Start with an audit. Take your agent's system prompt and ask: where are the safety constraints? Are they in the opening paragraph or buried at the bottom? Are they marked with RFC 2119 keywords or written as casual suggestions? Are sequential steps encoded with temporal markers or bare numbered lists? + +Then test. Run your agent through a session long enough to trigger compression. Check whether the post-compression behavior matches the pre-compression behavior. If your agent starts skipping review gates, reserving files speculatively, or force-pushing to shared branches after a long session, you have a compression-resilience problem. + +The six hardening techniques described here are available in the [Unbound Force replicator repository](https://github.com/unbound-force/replicator). The structural tests that verify compression resilience are in the same PRs. Fork them, adapt them, and apply them to your own agent prompts — before the compressor does it for you. diff --git a/content/docs/tutorials/_index.md b/content/docs/tutorials/_index.md new file mode 100644 index 0000000..efbd97d --- /dev/null +++ b/content/docs/tutorials/_index.md @@ -0,0 +1,13 @@ +--- +title: "Tutorials" +description: "Step-by-step guides for setting up and using Unbound Force tools — Dewey knowledge stores, Gaze CI integration, Pinkman scout, and more." +lead: "Hands-on guides that walk you through setup, configuration, and daily usage of the Unbound Force toolchain." +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 100 +toc: false +--- + +## Available Tutorials + +Browse the tutorials below to get started with specific tools and workflows. Each guide includes prerequisites, setup instructions, and verification steps. diff --git a/content/docs/tutorials/dewey-knowledge-stores.md b/content/docs/tutorials/dewey-knowledge-stores.md new file mode 100644 index 0000000..8c48000 --- /dev/null +++ b/content/docs/tutorials/dewey-knowledge-stores.md @@ -0,0 +1,328 @@ +--- +title: "Setting Up Dewey Knowledge Stores" +description: "Step-by-step guide to configuring and using Dewey's curated knowledge stores — from configuration to semantic search with quality-scored, source-traced knowledge." +lead: "Configure knowledge stores, run automated curation, and search structured knowledge extracted from your indexed sources." +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 10 +toc: true +--- + +## Prerequisites + +Before configuring knowledge stores, verify that you have the following tools installed and running. + +1. **Install Dewey v3.1.0 or later.** Knowledge stores require the curation pipeline introduced in v3.1.0. + + ```bash + brew install unbound-force/tap/dewey + dewey --version # Confirm v3.1.0+ + ``` + +2. **Start Ollama and pull a generation model.** Dewey uses a local LLM to extract structured knowledge from your indexed sources. The default model is `llama3.2:3b`. + + ```bash + ollama pull llama3.2:3b + ollama serve # Keep this running in a separate terminal + ``` + +3. **Configure and index at least one content source.** Knowledge stores curate from indexed sources. You need a populated `.uf/dewey/sources.yaml` with at least one source that has been indexed. + + ```bash + dewey index # Index all configured sources + ``` + + If you have not configured any sources yet, see the [Dewey Getting Started guide](/docs/getting-started/dewey/) before continuing. + +## Creating a Knowledge Store + +A knowledge store defines which indexed sources to curate and how to process them. Stores live in `.uf/dewey/knowledge-stores.yaml` at the root of your project. + +### Step 1: Create the configuration file + +Create or edit `.uf/dewey/knowledge-stores.yaml` in your project root: + +```bash +mkdir -p .uf/dewey +touch .uf/dewey/knowledge-stores.yaml +``` + +### Step 2: Define a store + +Each store has a `name`, a list of `sources` referencing source IDs from your `sources.yaml`, and optional settings that control curation behavior. + +```yaml +stores: + - name: team-knowledge + description: "Curated knowledge from team docs and design decisions" + sources: + - github-design-docs + - disk-meeting-notes + settings: + min_confidence: medium + extract_decisions: true + extract_patterns: true + + - name: api-reference + description: "Structured API knowledge from code and docs" + sources: + - github-api-repo + - web-api-docs + settings: + min_confidence: high + extract_decisions: false + extract_patterns: true +``` + +### Step 3: Understand the configuration fields + +- **`name`** — A unique identifier for the store. Use lowercase with hyphens. This name appears in search filters and output directories. +- **`description`** — A human-readable summary of what this store contains. Dewey displays this in status output. +- **`sources`** — A list of source IDs that match entries in your `sources.yaml`. Dewey curates only from these sources when processing this store. +- **`settings.min_confidence`** — The minimum confidence level for extracted knowledge to be included. Options: `high`, `medium`, `low`, `flagged`. Defaults to `medium`. +- **`settings.extract_decisions`** — Whether to extract decision records from source content. Defaults to `true`. +- **`settings.extract_patterns`** — Whether to extract recurring patterns and conventions. Defaults to `true`. + +## Running Curation + +Curation is the process of extracting structured knowledge from your indexed sources. Dewey reads the raw content, identifies decisions, patterns, and key facts, then scores each extraction for confidence and quality. + +### Full pipeline run + +Run curation across all configured stores: + +```bash +dewey curate +``` + +This processes every store defined in `knowledge-stores.yaml`. Dewey skips sources that have not changed since the last curation run. + +### Single store curation + +Target a specific store by name: + +```bash +dewey curate --store team-knowledge +``` + +This is useful when you have added new sources to one store and want to curate only that store without reprocessing others. + +### Force re-curation + +Re-curate all sources regardless of whether they have changed: + +```bash +dewey curate --force +``` + +Use this after upgrading Dewey, changing your generation model, or modifying store settings. The `--force` flag bypasses the change-detection cache and reprocesses every source. + +### Examine output + +Curated knowledge is stored in `.uf/dewey/knowledge/{store-name}/`. Each extraction is a Markdown file with frontmatter containing provenance metadata: + +```bash +ls .uf/dewey/knowledge/team-knowledge/ +``` + +```text +auth-design-decision-20260815.md +api-versioning-pattern-20260810.md +deployment-checklist-20260801.md +``` + +Each file contains the extracted knowledge, its confidence score, quality flags, and a link back to the original source document. + +## Understanding Quality Flags + +Dewey's curation pipeline assigns quality flags to extracted knowledge. These flags highlight areas where the extracted content may need human review or additional context. + +### Flag types + +| Flag | Meaning | +|------|---------| +| `missing_rationale` | A decision was extracted but no reasoning was stated in the source. The "why" is absent. | +| `implied_assumption` | The extraction depends on an assumption that is not explicitly stated in the source material. | +| `incongruent` | The extracted knowledge contradicts another piece of knowledge from a different source. | +| `unsupported_claim` | A factual claim was extracted but no supporting evidence or reference exists in the source. | + +### Confidence levels + +Every extraction receives a confidence score based on source quality, extraction clarity, and the presence or absence of quality flags: + +- **`high`** — Clean extraction from a well-structured source. No quality flags. Ready for use without review. +- **`medium`** — Reasonable extraction with minor ambiguity. May have one non-critical flag. Review recommended but not required. +- **`low`** — Extraction has multiple flags or comes from an ambiguous source. Human review is strongly recommended before relying on this knowledge. +- **`flagged`** — Extraction has a critical flag such as `incongruent` or `unsupported_claim`. Do not use without human verification. + +### Reviewing flagged content + +List all flagged extractions across your stores: + +```bash +dewey lint +``` + +The lint output includes a section for knowledge store quality. Address `incongruent` and `unsupported_claim` flags first — these indicate potential misinformation in your knowledge base. + +## Searching Curated Knowledge + +Once curation completes, curated knowledge is searchable through Dewey's semantic search with tier-based filtering. + +### Search curated content only + +Use the `tier` filter to restrict results to curated knowledge: + +```bash +dewey_semantic_search_filtered(query: "authentication flow", tier: "curated") +``` + +This returns only knowledge that has been through the curation pipeline — extracted, scored, and quality-checked. + +### Compare results across tiers + +Dewey organizes content into trust tiers. Each tier represents a different level of processing and validation: + +| Tier | Description | Use Case | +|------|-------------|----------| +| `authored` | Content you wrote directly (journal entries, manual notes) | Personal knowledge, session notes | +| `curated` | Machine-extracted and quality-scored knowledge from indexed sources | Structured team knowledge, decisions | +| `validated` | Curated knowledge that has been promoted after human review | High-trust reference material | +| `draft` | Raw learnings stored via `dewey_store_learning` before compilation | Work-in-progress insights | +| `untrusted` | Unverified external content | Background research, third-party docs | + +Search a specific tier: + +```bash +dewey_semantic_search_filtered(query: "deployment strategy", tier: "authored") +dewey_semantic_search_filtered(query: "deployment strategy", tier: "curated") +dewey_semantic_search_filtered(query: "deployment strategy", tier: "draft") +``` + +Comparing results across tiers reveals gaps. If a topic appears in `authored` notes but not in `curated` knowledge, the source documents may lack formal documentation for that topic. + +## Configuring Background Curation + +Dewey can run curation automatically so your knowledge stores stay current without manual intervention. + +### Curation interval + +Set the `curation_interval` field in your store configuration to control how often Dewey re-curates: + +```yaml +stores: + - name: team-knowledge + sources: + - github-design-docs + settings: + curation_interval: 10m # Default: 10 minutes +``` + +Dewey checks for source changes at this interval. If no sources have changed, the curation cycle is a no-op. Set a longer interval (e.g., `1h`) for large source sets to reduce CPU usage. + +### Curate on index + +Enable `curate_on_index` to trigger curation immediately after a source is indexed: + +```yaml +stores: + - name: team-knowledge + sources: + - github-design-docs + settings: + curate_on_index: true +``` + +This ensures curated knowledge is always up to date with the latest indexed content. It adds latency to the indexing step but eliminates the delay between indexing and curation. + +### Generation model + +Dewey uses a local LLM for knowledge extraction. Set the model with the `DEWEY_GENERATION_MODEL` environment variable: + +```bash +export DEWEY_GENERATION_MODEL=llama3.2:3b # Default +``` + +Larger models produce higher-quality extractions but require more memory and processing time. The default `llama3.2:3b` balances quality and speed for most workloads. If you have the hardware, `llama3.1:8b` improves extraction accuracy for complex technical content. + +## Monitoring with `dewey lint` + +The `dewey lint` command includes knowledge store quality metrics alongside its other checks. Run it regularly to monitor the health of your curated knowledge. + +```bash +dewey lint +``` + +### Knowledge store metrics + +The lint output includes a dedicated section for each knowledge store: + +```text +Knowledge Store: team-knowledge + Total extractions: 47 + Confidence distribution: + high: 28 (59.6%) + medium: 12 (25.5%) + low: 5 (10.6%) + flagged: 2 (4.3%) + Quality flags: + missing_rationale: 3 + implied_assumption: 4 + incongruent: 1 + unsupported_claim: 1 + Uncompiled learnings: 6 +``` + +### What to act on + +1. **High `flagged` percentage** — If more than 10% of extractions are flagged, review your source quality. Poorly structured sources produce unreliable extractions. +2. **`incongruent` flags** — These indicate contradictions between sources. Resolve them by updating the outdated source or adding clarifying context. +3. **`unsupported_claim` flags** — These indicate claims without evidence. Either add supporting references to the source or remove the claim. +4. **Uncompiled learnings** — Run `dewey compile` to synthesize draft learnings into compiled knowledge articles. + +## Storing Ad-Hoc Knowledge with `/dewey-store` + +Not all knowledge comes from indexed sources. Use the `/dewey-store` command to capture insights, decisions, and patterns directly from conversations and ad-hoc observations. + +### Fully specified mode + +Provide the tag and category explicitly when you know exactly how to classify the knowledge: + +```text +/dewey-store --tag auth-design --category decision +"We chose JWT over session cookies because our API serves both browser and CLI clients." +``` + +This creates a learning tagged with `auth-design` and categorized as a `decision`. Available categories: `decision`, `pattern`, `gotcha`, `context`, `reference`. + +### Suggested mode + +Let the agent propose a tag and category based on the content: + +```text +/dewey-store +"The curation pipeline skips sources with fewer than 100 tokens to avoid noise." +``` + +The agent analyzes the content and suggests an appropriate tag (e.g., `curation-pipeline`) and category (e.g., `pattern`). You confirm or override before the learning is stored. + +### Extract mode + +Use `--extract` to process long threads and pull out the key insights: + +```text +/dewey-store --extract + +``` + +Extract mode identifies the most important decisions, patterns, and action items from the pasted content. Each extraction is stored as a separate learning with its own tag and category. This is useful for capturing knowledge from lengthy discussions without manually summarizing each point. + +### Verifying stored knowledge + +After storing ad-hoc knowledge, verify it appears in search results: + +```bash +dewey_semantic_search(query: "JWT authentication") +``` + +Stored learnings are immediately searchable. They start in the `draft` tier and move to `validated` after human review via `dewey promote`. diff --git a/content/docs/tutorials/dewey-provider-configuration.md b/content/docs/tutorials/dewey-provider-configuration.md new file mode 100644 index 0000000..a7533c5 --- /dev/null +++ b/content/docs/tutorials/dewey-provider-configuration.md @@ -0,0 +1,285 @@ +--- +title: "Configuring Dewey Embedding and Synthesis Providers" +description: "Step-by-step guide for configuring Dewey's pluggable embedding and synthesis providers — covering both Ollama (default, local) and Vertex AI (cloud)." +lead: "Switch between local Ollama and cloud Vertex AI for embeddings and synthesis. Mix providers for the best of both worlds." +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 20 +toc: true +--- + +## Prerequisites + +Before configuring providers, make sure you have Dewey installed and the provider-specific dependencies ready. + +**Dewey installation** — install via Homebrew or Go: + +```bash +# Homebrew +brew install unbound-force/tap/dewey + +# Or from source +go install github.com/unbound-force/dewey/cmd/dewey@latest +``` + +**For Ollama (local embeddings and synthesis):** + +1. Install Ollama from [ollama.com](https://ollama.com). +2. Pull an embedding model: + +```bash +ollama pull nomic-embed-text +``` + +3. Verify Ollama is running: + +```bash +ollama list +``` + +**For Vertex AI (cloud embeddings and synthesis):** + +1. Create or select a GCP project with the Vertex AI API enabled. +2. Install the `gcloud` CLI from [cloud.google.com/sdk](https://cloud.google.com/sdk). +3. Authenticate with application default credentials: + +```bash +gcloud auth application-default login +gcloud config set project your-project-id +``` + +## Default Setup (Ollama) + +Dewey works out of the box with Ollama — no configuration file required. When you run Dewey without a `config.yaml`, it connects to Ollama on `localhost:11434` and uses `nomic-embed-text` for embeddings. + +Start Ollama, then run Dewey: + +```bash +ollama serve & +dewey serve +``` + +Dewey automatically detects the local Ollama instance and begins generating embeddings for your vault content. No API keys, no cloud credentials, no YAML files. This is the fastest path from install to working semantic search. + +## Configuring Vertex AI Embeddings + +Vertex AI embeddings use Google's `text-embedding-005` model, which produces higher-quality vectors than local models for most workloads. The trade-off is network latency and GCP billing. + +### Step 1: Authenticate with GCP + +Ensure your application default credentials are set: + +```bash +gcloud auth application-default login +``` + +### Step 2: Create or edit your vault-level config + +Create a `config.yaml` in your Dewey vault directory (the directory containing your Logseq graph): + +```yaml +embedding: + provider: vertexai + model: text-embedding-005 + project: your-project-id + location: us-central1 +``` + +### Step 3: Reindex your vault + +Switching embedding providers changes the vector space. Existing embeddings are incompatible with the new model's dimensions. You must reindex: + +```bash +dewey reindex +``` + +This regenerates all embeddings using the Vertex AI model. Depending on vault size, this may take several minutes and incur GCP API costs. + +### Step 4: Verify + +Run a semantic search to confirm the new embeddings are working: + +```bash +dewey search "your test query" +``` + +You should see results ranked by the Vertex AI embedding model's similarity scores. + +## Configuring Vertex AI Synthesis + +Synthesis is the provider Dewey uses for compiling learnings into knowledge articles. Vertex AI synthesis uses Claude models via Google's `rawPredict` endpoint, giving you access to Anthropic's models through your GCP project. + +### Step 1: Add synthesis configuration + +Add the `synthesis` block to your `config.yaml`: + +```yaml +synthesis: + provider: vertexai + model: claude-sonnet-4-20250514 + project: your-project-id + location: us-east5 +``` + +The `location` for synthesis may differ from your embedding location. Claude models on Vertex AI are available in specific regions — check [Google's model availability docs](https://cloud.google.com/vertex-ai/docs/general/locations) for current region support. + +### Step 2: Verify credentials + +Synthesis uses the same application default credentials as embeddings. If you already authenticated for embedding configuration, no additional credential setup is needed. + +### Step 3: Test compilation + +Trigger a compile to verify synthesis works: + +```bash +dewey compile +``` + +Dewey will use the configured Claude model to synthesize stored learnings into compiled knowledge articles. + +## Mixing Providers + +The recommended production setup uses Ollama for embeddings and Vertex AI for synthesis. This combination keeps embedding generation fast and local (no network round-trips, no per-query costs) while using Claude's superior language capabilities for knowledge synthesis. + +### Recommended hybrid config + +```yaml +embedding: + provider: ollama + model: nomic-embed-text + +synthesis: + provider: vertexai + model: claude-sonnet-4-20250514 + project: your-project-id + location: us-east5 +``` + +This setup means: + +- **Embeddings** are generated locally by Ollama. Indexing and semantic search stay fast and free. +- **Synthesis** uses Claude via Vertex AI. Compilation produces higher-quality knowledge articles. +- **No reindex required** if you were already using Ollama for embeddings — the vector space hasn't changed. + +You can also reverse the mix (Vertex AI embeddings + Ollama synthesis), though this is less common. The key constraint is that embedding and synthesis providers are fully independent — changing one does not affect the other. + +## Global Config + +For developers working across multiple Dewey vaults, a global configuration file avoids duplicating provider settings in every vault. + +### Step 1: Create the global config directory + +```bash +mkdir -p ~/.config/dewey +``` + +### Step 2: Add your global config + +Create `~/.config/dewey/config.yaml` with your shared provider settings: + +```yaml +embedding: + provider: ollama + model: nomic-embed-text + +synthesis: + provider: vertexai + model: claude-sonnet-4-20250514 + project: your-project-id + location: us-east5 +``` + +### Step 3: Override per vault (optional) + +Any vault-level `config.yaml` takes precedence over the global config. Place a `config.yaml` in a specific vault directory to override global settings for that vault only. + +This is useful when one vault needs a different embedding model or a different GCP project for billing isolation. + +## Config Precedence + +Dewey resolves configuration from three sources, but the precedence rules differ between embedding and synthesis. This asymmetry is a deliberate backward-compatibility decision. + +### Embedding precedence (env vars win) + +For embedding configuration, environment variables override the config file: + +1. **Environment variables** (highest priority) — `DEWEY_EMBEDDING_PROVIDER`, `DEWEY_EMBEDDING_MODEL`, `DEWEY_VERTEX_PROJECT`, `DEWEY_VERTEX_LOCATION` +2. **Vault-level config** — `config.yaml` in the vault directory +3. **Global config** (lowest priority) — `~/.config/dewey/config.yaml` + +```bash +# Force Ollama embeddings regardless of config file +DEWEY_EMBEDDING_PROVIDER=ollama dewey serve +``` + +### Synthesis precedence (config file wins) + +For synthesis configuration, the config file takes priority and environment variables serve as fallback only: + +1. **Vault-level config** (highest priority) — `config.yaml` in the vault directory +2. **Global config** — `~/.config/dewey/config.yaml` +3. **Environment variables** (lowest priority, fallback only) — `DEWEY_SYNTHESIS_PROVIDER`, `DEWEY_SYNTHESIS_MODEL` + +This means setting `DEWEY_SYNTHESIS_PROVIDER=ollama` in your environment has no effect if your `config.yaml` specifies `synthesis.provider: vertexai`. The config file wins. + +### Why the asymmetry? + +Embedding provider selection was originally controlled exclusively through environment variables. When config file support was added, environment variables retained their override behavior to avoid breaking existing setups. Synthesis support was added later with config-file-first semantics from the start. The result is an intentional asymmetry that preserves backward compatibility for embedding users while giving synthesis users the cleaner config-file-first model. + +## Troubleshooting + +### Credential errors with Vertex AI + +**Symptom:** `could not find default credentials` or `permission denied` errors when using Vertex AI. + +**Fix:** + +1. Re-authenticate with application default credentials: + +```bash +gcloud auth application-default login +``` + +2. Verify your project is set correctly: + +```bash +gcloud config get-value project +``` + +3. Confirm the Vertex AI API is enabled in your GCP project: + +```bash +gcloud services list --enabled | grep aiplatform +``` + +If the API is not listed, enable it: + +```bash +gcloud services enable aiplatform.googleapis.com +``` + +### Model not found + +**Symptom:** `model not found` errors during embedding or synthesis. + +**Fix for Ollama:** Pull the model explicitly: + +```bash +ollama pull nomic-embed-text +``` + +**Fix for Vertex AI:** Verify the model name matches a supported model in your configured region. Model availability varies by region — `text-embedding-005` and Claude models are not available in every Vertex AI location. + +### Dimension mismatch after provider switch + +**Symptom:** Semantic search returns no results or garbage results after switching embedding providers. + +**Cause:** Different embedding models produce vectors with different dimensions. Ollama's `nomic-embed-text` produces 768-dimensional vectors. Vertex AI's `text-embedding-005` produces 768-dimensional vectors by default but can be configured for other dimensions. If you switch between models with different output dimensions, the existing vector index becomes incompatible. + +**Fix:** Reindex your entire vault after any embedding provider change: + +```bash +dewey reindex +``` + +This drops all existing embeddings and regenerates them with the new model. The operation is safe — it does not modify your vault content, only the derived vector index. diff --git a/content/docs/tutorials/gaze-crap-baseline-ci.md b/content/docs/tutorials/gaze-crap-baseline-ci.md new file mode 100644 index 0000000..3ccab93 --- /dev/null +++ b/content/docs/tutorials/gaze-crap-baseline-ci.md @@ -0,0 +1,200 @@ +--- +title: "Setting Up CRAP Baseline Comparison in CI" +description: "Step-by-step tutorial for setting up per-function CRAP regression detection using gaze's baseline comparison feature in GitHub Actions." +lead: "Detect CRAP score regressions on every PR. Create a baseline, add a CI step, and gaze handles the rest — zero wrapper scripts required." +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 30 +toc: true +--- + +## Prerequisites + +Before you begin, make sure you have the following in place: + +1. **gaze installed** — Install via Homebrew or Go: + + ```bash + # Homebrew (macOS/Linux) + brew install unbound-force/tap/gaze + + # Or install from source + go install github.com/unbound-force/gaze/cmd/gaze@latest + ``` + +2. **A Go project with tests** — gaze computes CRAP scores from coverage data, so your project needs a test suite that produces a Go coverage profile. + +3. **A CI pipeline using GitHub Actions** — The examples in this tutorial target GitHub Actions, but the baseline comparison feature works in any CI system that can run shell commands. + +## Create the Initial Baseline + +The baseline is a JSON snapshot of every function's CRAP score in your project. gaze compares future runs against this snapshot to detect regressions. + +1. Run your tests and generate a coverage profile: + + ```bash + go test -coverprofile=coverage.out ./... + ``` + +2. Generate the baseline file: + + ```bash + mkdir -p .gaze + gaze crap --format=json --coverprofile=coverage.out ./... > .gaze/baseline.json + ``` + +3. Commit the baseline to version control: + + ```bash + git add .gaze/baseline.json + git commit -m "chore: add gaze CRAP baseline" + git push + ``` + +The baseline file captures the CRAP score for every function in your codebase at this point in time. All future CI runs compare against these scores to flag regressions. + +## CI Integration + +gaze auto-detects the baseline file at `.gaze/baseline.json`. When the file exists, gaze automatically compares current scores against it and reports regressions — no extra flags or wrapper scripts required. + +Add a CRAP regression check step to your GitHub Actions workflow: + +```yaml +name: CRAP Regression Check + +on: + pull_request: + branches: [main] + +permissions: + contents: read + +jobs: + crap-check: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Set up Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + with: + go-version-file: go.mod + + - name: Install gaze + run: go install github.com/unbound-force/gaze/cmd/gaze@latest + + - name: Run tests with coverage + run: go test -coverprofile=coverage.out -count=1 -race ./... + + - name: Check CRAP regressions + run: gaze crap --coverprofile=coverage.out ./... +``` + +The final step runs gaze with the coverage profile. Because `.gaze/baseline.json` exists in the repository, gaze automatically loads it and compares every function's current CRAP score against the baseline. If any function regressed, gaze exits with a non-zero status code and the CI step fails. + +## Understanding the Output + +When gaze detects differences between the current run and the baseline, it classifies each function into one of four categories: + +- **Regression** — The function's CRAP score increased beyond the epsilon threshold. This fails CI. +- **Improvement** — The function's CRAP score decreased. This is informational and does not fail CI. +- **New** — The function did not exist in the baseline. gaze applies the new-function threshold (default: 30) to decide whether this fails CI. +- **Removed** — The function existed in the baseline but no longer exists. This is informational. + +Here is an example of gaze output with baseline comparison: + +```text +CRAP Baseline Comparison +======================== + +Regressions (score increased): + internal/parser.Parse 12.4 → 38.7 (+26.3) FAIL + internal/parser.Validate 8.1 → 15.2 (+7.1) FAIL + +Improvements (score decreased): + internal/lexer.Tokenize 22.0 → 6.3 (-15.7) + +New functions: + internal/parser.Normalize 4.2 PASS (below threshold 30) + internal/parser.Transform 42.8 FAIL (above threshold 30) + +Removed functions: + internal/parser.OldParse (was 18.3) + +Summary: 3 regressions, 1 improvement, 2 new, 1 removed +Exit code: 1 (regressions detected) +``` + +Regressions and new functions above the threshold cause a non-zero exit code. Improvements and removals are reported but do not block the pipeline. + +## Tuning Sensitivity + +gaze uses two thresholds to control sensitivity: + +- **Epsilon** (default: `0.5`) — The minimum score increase that counts as a regression. Small fluctuations below this value are ignored. Raise this value if you see false positives from minor refactors. +- **New function threshold** (default: `30`) — The maximum CRAP score allowed for functions that do not appear in the baseline. Lower this value to enforce stricter standards on new code. + +Configure both values in a `.gaze.yaml` file at the root of your repository: + +```yaml +crap: + baseline: + epsilon: 1.0 + new_threshold: 20 +``` + +With this configuration, a function must increase by more than 1.0 CRAP points to trigger a regression, and new functions must score below 20 to pass. Commit `.gaze.yaml` alongside your baseline so that all contributors and CI use the same thresholds. + +## Refreshing the Baseline + +The baseline represents your accepted CRAP scores at a point in time. Refresh it when the current scores no longer reflect reality: + +- **After a release** — Lock in the post-release scores as the new standard. +- **After intentional complexity changes** — If you deliberately added complexity (e.g., expanded a parser), update the baseline so future runs compare against the new expected scores. +- **After large-scale refactoring** — A refactor that improves many functions should be captured so you get credit for the improvements. + +To refresh the baseline: + +1. Run the tests and regenerate the baseline: + + ```bash + go test -coverprofile=coverage.out ./... + gaze crap --format=json --coverprofile=coverage.out ./... > .gaze/baseline.json + ``` + +2. Commit and push the updated baseline: + + ```bash + git add .gaze/baseline.json + git commit -m "chore: refresh gaze CRAP baseline" + git push + ``` + +Do not refresh the baseline on every PR. The baseline should change deliberately, not as a side effect of routine development. Frequent refreshes defeat the purpose of regression detection. + +## Troubleshooting + +### Stale Baseline + +**Symptom**: gaze reports many "removed" functions and unexpected "new" functions. + +**Cause**: The baseline was generated from a significantly older version of the codebase. Function signatures, package paths, or file locations changed since the baseline was created. + +**Fix**: Regenerate the baseline from the current `main` branch and commit it. Going forward, refresh the baseline after major structural changes. + +### Config Drift + +**Symptom**: CI fails with regressions that pass locally, or vice versa. + +**Cause**: The `.gaze.yaml` file on your local machine differs from the one in the repository, or you have local environment variables that override gaze settings. + +**Fix**: Ensure `.gaze.yaml` is committed to the repository and that you pull the latest version before running gaze locally. Do not rely on local-only configuration for thresholds. + +### Function Renames + +**Symptom**: A renamed function appears as both "removed" (old name) and "new" (new name). The new entry may fail if it exceeds the new-function threshold. + +**Cause**: gaze identifies functions by their fully qualified name (`package.Function`). A rename creates a new identity that has no baseline entry. + +**Fix**: Refresh the baseline after renaming functions. If you rename functions frequently during a refactoring PR, refresh the baseline in a preparatory commit on `main` before opening the refactoring PR. diff --git a/content/docs/tutorials/onboard-customization.md b/content/docs/tutorials/onboard-customization.md new file mode 100644 index 0000000..856ed3e --- /dev/null +++ b/content/docs/tutorials/onboard-customization.md @@ -0,0 +1,312 @@ +--- +title: "Getting Started with /onboard — Customizing Your Hero Experience" +description: "Step-by-step tutorial for using the /onboard command to capture your preferences and customize how Unbound Force heroes respond to your working style." +lead: "Tell the heroes what matters to you. /onboard captures your inspiration, interests, and objectives into a profile that every hero reads — so they work the way you work." +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 50 +toc: true +--- + +## Prerequisites + +Before running `/onboard`, confirm that your environment meets these requirements: + +1. **Run `uf init` first.** The `/onboard` command writes your profile to `.uf/onboarding/profile.md`. The `.uf/` directory must exist, and `uf init` creates it along with the rest of your project scaffold. +2. **Have OpenCode running.** The `/onboard` command is an interactive interview conducted through your OpenCode session. Start OpenCode in your project directory before proceeding. + +If you skip `uf init`, the onboarding interview will fail because the `.uf/onboarding/` directory does not exist. Run `uf init` first, then return here. + +## Running /onboard + +Type `/onboard` in your OpenCode session to start the interview. The command walks you through three phases — Inspiration, Interests, and Objectives — each designed to capture a different dimension of how you work. + +### Phase 1: Inspiration + +The first phase asks: **What inspires your approach to engineering? What projects, books, or ideas shape how you think about building software?** + +This is not a quiz. There are no wrong answers. The heroes use your inspiration sources to calibrate their communication style and technical references. If you admire the Unix philosophy, heroes will favor composable, single-purpose designs. If you draw from domain-driven design, heroes will use bounded-context language in their proposals. + +```text +> /onboard + +Welcome! Let's build your hero profile. + +Phase 1 of 3: Inspiration + +What inspires your approach to engineering? Think about +projects you admire, books that shaped your thinking, +or ideas that guide how you build software. + +> I admire the Go standard library for its simplicity. +> "A Philosophy of Software Design" by John Ousterhout +> changed how I think about complexity. I also draw from +> the Erlang/OTP model of fault tolerance — let it crash, +> supervise, restart. + +Got it. Simplicity-first design, deep module philosophy, +and fault-tolerant supervision patterns. Moving on. +``` + +Answer in your own words. Write a sentence or a paragraph — the interview adapts to whatever level of detail you provide. + +### Phase 2: Interests + +The second phase asks: **What technical areas fascinate you? What do you want to learn more about?** + +Heroes use your interests to prioritize explanations and suggest approaches that align with what you care about. If you express interest in observability, Gaze will surface metrics and tracing patterns more prominently. If you mention distributed systems, Muti-Mind will lean toward event-driven architectures when multiple approaches are viable. + +```text +Phase 2 of 3: Interests + +What technical areas fascinate you? What do you want +to learn more about? + +> I'm deep into observability — structured logging, +> distributed tracing, SLO-based alerting. I also want +> to learn more about formal verification and property- +> based testing. WebAssembly interests me but I haven't +> built anything with it yet. + +Noted. Strong observability background, curiosity about +formal methods and property-based testing, early interest +in WebAssembly. Next phase. +``` + +### Phase 3: Objectives + +The third phase asks: **What are you trying to achieve with your current project? What outcomes matter most?** + +This phase grounds the profile in your immediate goals. Heroes read your objectives before every session to understand what "done" looks like for you. Concrete objectives produce better hero behavior than abstract ones. + +```text +Phase 3 of 3: Objectives + +What are you trying to achieve with your current project? +What outcomes matter most? + +> I'm building a CLI tool for compliance automation. +> The MVP needs to parse OSCAL catalogs, generate control +> assessments, and produce human-readable reports. Ship +> date is Q3. Quality matters more than speed — I'd +> rather slip a week than ship with flaky tests. + +Clear. Compliance automation CLI, OSCAL-based, quality +over velocity, Q3 target. Profile complete. + +Writing profile to .uf/onboarding/profile.md... +Done. Every hero will read this profile at session start. +``` + +## Understanding the Profile + +After the interview completes, `/onboard` writes your profile to `.uf/onboarding/profile.md`. The file has two parts: YAML frontmatter for structured metadata, and a Markdown body for narrative content. + +### YAML Frontmatter Fields + +The frontmatter captures machine-readable metadata that heroes parse programmatically: + +| Field | Purpose | Example | +|-------|---------|---------| +| `created` | Timestamp of initial onboarding | `2026-08-23T14:30:00Z` | +| `updated` | Timestamp of most recent update | `2026-08-23T14:30:00Z` | +| `version` | Profile schema version | `1` | +| `status` | Whether the profile is complete | `complete` or `draft` | +| `interview_phases_completed` | Which phases finished | `[inspiration, interests, objectives]` | + +### Markdown Body Sections + +The body contains four sections that heroes read as natural language: + +- **Inspiration**: Your engineering influences, distilled into themes the heroes reference when proposing designs or explaining trade-offs. +- **Interests**: Your technical fascinations, used to weight explanations and surface relevant patterns. +- **Objectives**: Your project goals and success criteria, consulted before every planning and implementation session. +- **Hero Mapping**: Auto-generated section that maps your profile themes to specific hero behaviors. This section updates each time you re-run `/onboard`. + +### Sample Profile + +```markdown +--- +created: 2026-08-23T14:30:00Z +updated: 2026-08-23T14:30:00Z +version: 1 +status: complete +interview_phases_completed: [inspiration, interests, objectives] +--- + +## Inspiration + +Simplicity-first design inspired by the Go standard library. +Deep module philosophy from "A Philosophy of Software Design" +by John Ousterhout. Fault-tolerant supervision patterns from +Erlang/OTP — let it crash, supervise, restart. + +## Interests + +Strong background in observability: structured logging, +distributed tracing, SLO-based alerting. Exploring formal +verification and property-based testing. Early interest in +WebAssembly. + +## Objectives + +Building a CLI tool for compliance automation. MVP scope: +parse OSCAL catalogs, generate control assessments, produce +human-readable reports. Target ship date: Q3 2026. Quality +over velocity — prefer slipping schedule to shipping flaky +tests. + +## Hero Mapping + +- **Cobalt-Crush**: Favor deep modules over shallow wrappers. + Use Go standard library idioms. Inject dependencies for + testability. +- **Muti-Mind**: Propose event-driven patterns where applicable. + Prioritize observability hooks in architectural decisions. +- **The Divisor**: Weight code clarity and test coverage in + reviews. Flag complexity that contradicts the simplicity-first + principle. +- **Gaze**: Surface CRAP scores and coverage gaps. Align quality + thresholds with the "quality over velocity" objective. +``` + +## How Heroes Use the Profile + +Every hero reads your profile at the start of each session. The profile changes how heroes communicate, what patterns they propose, and which trade-offs they prioritize. Here are concrete examples. + +### Cobalt-Crush: Implementation Style + +**Without a profile**, Cobalt-Crush uses generic best practices: + +```go +// ProcessCatalog handles catalog processing. +func ProcessCatalog(path string) (*Result, error) { + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + // ... processing logic +} +``` + +**With your profile** (simplicity-first, deep modules, testability), Cobalt-Crush injects the file reader and builds a deeper API surface: + +```go +// ProcessCatalog parses an OSCAL catalog from the given reader and returns +// a structured assessment result. The reader abstraction allows testing +// without filesystem access — aligned with the deep module philosophy +// where the interface is narrow but the implementation handles complexity. +func ProcessCatalog(r io.Reader, opts ...Option) (*Result, error) { + cfg := defaultConfig() + for _, opt := range opts { + opt(&cfg) + } + // ... processing logic with cfg-driven behavior +} +``` + +### Muti-Mind: Architecture Proposals + +**Without a profile**, Muti-Mind proposes standard layered architecture. + +**With your profile** (observability interest, fault tolerance inspiration), Muti-Mind proposes architectures that include tracing hooks and supervision trees: + +> "Given your interest in observability and Erlang-style supervision, I recommend structuring the pipeline as a supervisor that spawns worker goroutines per catalog. Each worker emits structured trace spans. If a worker panics, the supervisor logs the failure, restarts processing for that catalog, and continues. This aligns with your 'let it crash' principle while maintaining the observability you care about." + +### The Divisor: Review Focus + +**Without a profile**, The Divisor applies uniform review criteria. + +**With your profile** (quality over velocity, simplicity-first), The Divisor adjusts its severity weighting: + +> "This function has a CRAP score of 42. Normally I'd flag this as MEDIUM, but your profile states 'quality matters more than speed' and draws from simplicity-first design. Elevating to HIGH. Recommend splitting the validation logic into a pure function that returns a typed error, then testing that function independently." + +### Gaze: Quality Thresholds + +**Without a profile**, Gaze uses project-default coverage thresholds. + +**With your profile** (quality over velocity), Gaze tightens its recommendations: + +> "Your profile prioritizes quality over velocity. I recommend setting the coverage ratchet to prevent regression rather than targeting a fixed percentage. Current coverage is 78% — I'll flag any PR that drops below this baseline." + +## Updating Your Profile + +### Re-running /onboard in Update Mode + +Run `/onboard` again at any time to update your profile. The command detects the existing profile and enters update mode instead of starting fresh. + +1. Type `/onboard` in your OpenCode session. +2. The command displays your current profile and asks which phases you want to revisit. +3. Select one or more phases to update. Phases you skip retain their existing content. +4. Complete the selected phases with your updated responses. +5. The command writes the updated profile with a new `updated` timestamp. + +```text +> /onboard + +Existing profile found (created 2026-08-23). + +Which phases do you want to update? + [1] Inspiration + [2] Interests + [3] Objectives + [a] All phases + [q] Cancel + +> 3 + +Phase 3 of 3: Objectives (updating) + +Current objectives: + Building a CLI tool for compliance automation... + +What are your updated objectives? + +> Same project, but scope expanded. We now need to +> support SSP generation in addition to assessments. +> Ship date moved to Q4. Quality bar unchanged. + +Updated. Writing profile to .uf/onboarding/profile.md... +Done. +``` + +### Profile History Snapshots + +Each time you update your profile, `/onboard` saves a timestamped snapshot in `.uf/onboarding/history/`. Snapshots let you track how your goals and interests evolve over time. Heroes read only the current profile — snapshots exist for your reference. + +```text +.uf/onboarding/ +├── profile.md # Current profile (heroes read this) +└── history/ + ├── profile-2026-08-23T143000Z.md # Initial profile + └── profile-2026-09-15T091500Z.md # After objectives update +``` + +## Edge Cases + +### Abandoned Interviews + +If you stop the interview before completing all three phases, `/onboard` saves a partial profile with `status: draft` in the frontmatter. The `interview_phases_completed` field lists only the phases you finished. + +Heroes still read draft profiles. They use whatever information is available and apply defaults for missing phases. You will see a reminder at the start of each session: + +```text +Note: Your onboarding profile is incomplete (missing: objectives). +Run /onboard to finish the interview. +``` + +Resume the interview by running `/onboard` again. The command picks up where you left off — it does not repeat completed phases unless you explicitly choose to update them. + +### Missing Heroes + +Your profile works regardless of which heroes are installed. If you reference a hero that is not present in your project (for example, you mention Gaze but have not installed it), the Hero Mapping section still generates an entry for that hero. The entry is ignored at runtime and activates automatically if you install the hero later. + +Remove a hero from your project and the profile continues to function. Add a hero and it reads your existing profile immediately — no re-onboarding required. + +### Draft vs. Complete Profiles + +A **draft** profile has `status: draft` and is missing one or more interview phases. Heroes read draft profiles but may ask clarifying questions during sessions to fill gaps. For example, if the Objectives phase is missing, Cobalt-Crush may ask "What are you trying to build?" before starting implementation. + +A **complete** profile has `status: complete` and all three phases finished. Heroes read complete profiles without additional questions. Complete profiles produce the most consistent hero behavior because every hero has the full context from the start. + +Upgrade a draft to complete by running `/onboard` and finishing the remaining phases. The status field updates automatically when all three phases are present. diff --git a/content/docs/tutorials/pinkman-oss-scout.md b/content/docs/tutorials/pinkman-oss-scout.md new file mode 100644 index 0000000..6d19b47 --- /dev/null +++ b/content/docs/tutorials/pinkman-oss-scout.md @@ -0,0 +1,234 @@ +--- +title: "Getting Started with Pinkman OSS Scout" +description: "Step-by-step tutorial for using Pinkman's /scout command to discover, evaluate, audit, and report on open source projects for adoption." +lead: "Evaluate open source projects before adopting them. /scout gives you license compatibility, maintenance health, dependency analysis, and structured adoption recommendations." +date: 2026-08-23T00:00:00+00:00 +draft: false +weight: 40 +toc: true +--- + +## Prerequisites + +Before using `/scout`, complete these setup steps: + +1. Run `uf init` in your project root. This scaffolds the `pinkman.md` agent file alongside your other Unbound Force agents. Pinkman handles open source intelligence — license analysis, maintenance health checks, and adoption recommendations. + +2. Start Dewey if you want cross-session memory. Dewey is optional but recommended. When running, Pinkman stores every evaluation as a learning, so future scouting sessions draw on past analysis instead of starting from scratch. + +3. Verify Pinkman is available by checking that `.opencode/agents/pinkman.md` exists in your project. The agent activates automatically when you invoke any `/scout` command. + +## Discover Mode + +Discover mode is the default. Use it to find open source projects by keyword, filtered for license compatibility with your project. + +### Find Projects by Keyword + +1. Run the scout command with a topic: + +```bash +/scout static analysis Go +``` + +2. Pinkman searches GitHub for projects matching your query. It filters results against your project's license (detected from `LICENSE` or `go.mod`) and returns a ranked list. + +3. Review the output. Each result includes the project name, license verdict, star count, last commit date, and a one-line summary of what the project does. + +### Example Output + +``` +🔍 Scouting: "static analysis Go" +License context: Apache-2.0 (from LICENSE) + + # │ Project │ License │ Compat │ Stars │ Last Commit │ Summary + 1 │ golangci/golangci-lint │ GPL-3.0 │ ⚠ WEAK │ 15.2k│ 2 days ago │ Fast Go linters runner + 2 │ dominikh/go-tools │ MIT │ ✅ OK │ 6.1k │ 5 days ago │ Staticcheck and related tools + 3 │ mgechev/revive │ MIT │ ✅ OK │ 4.8k │ 1 week ago │ Extensible Go linter framework + 4 │ securego/gosec │ Apache-2.0 │ ✅ OK │ 7.6k │ 3 days ago │ Security-focused Go source scanner + +Found 4 projects. Use /scout --report for a full evaluation. +``` + +Pinkman marks GPL-3.0 as `⚠ WEAK` compatibility when your project uses Apache-2.0. This does not mean you cannot use the project — it means you need to evaluate the integration boundary (binary vs. library linking) before adopting it. + +## Understanding Results + +### License Verdicts and Compatibility Tiers + +Pinkman classifies license compatibility into three tiers: + +- **✅ OK** — The dependency's license is fully compatible with your project's license. No restrictions on how you integrate it. +- **⚠ WEAK** — The dependency's license imposes conditions that may conflict with your project's license. Review the specific terms before adopting. Common examples: GPL libraries used in Apache-2.0 projects, or AGPL services called over the network. +- **❌ BLOCK** — The dependency's license is incompatible with your project's license. Adopting it would require relicensing your project or isolating the dependency behind a process boundary. + +### Dependency Lists and Overlap Tables + +When Pinkman evaluates multiple projects in the same session, it generates an overlap table. This table shows shared transitive dependencies across candidates. High overlap means adopting multiple projects adds minimal dependency weight. Low overlap means each project brings its own dependency tree, increasing your supply chain surface area. + +``` +Dependency Overlap (2 of 4 candidates share deps): + + Dependency │ golangci-lint │ revive │ gosec + golang.org/x/tools │ ✓ │ ✓ │ ✓ + golang.org/x/mod │ ✓ │ ✓ │ ✗ + github.com/fatih/color│ ✓ │ ✗ │ ✗ +``` + +Use this table to minimize the number of new transitive dependencies your project takes on. + +## Trend Mode + +Trend mode identifies projects gaining momentum. Use it to spot emerging tools before they become mainstream. + +### Identify Trending Projects + +1. Run the scout command with the `--trend` flag: + +```bash +/scout --trend MCP servers +``` + +2. Pinkman queries GitHub's trending data and cross-references it with star velocity, fork rate, and contributor growth over the past 30 days. + +3. Review the quantitative indicators. Each result includes growth metrics alongside the standard project metadata. + +### Example Output + +``` +📈 Trending: "MCP servers" (30-day window) + + # │ Project │ ⭐ Velocity │ 🍴 Forks/mo │ 👥 New Contributors │ License │ Summary + 1 │ modelcontextprotocol/servers │ +2,340 │ +187 │ +42 │ MIT │ Reference MCP server implementations + 2 │ punkpeye/awesome-mcp-servers │ +1,890 │ +95 │ +18 │ CC0-1.0 │ Curated list of MCP servers + 3 │ mark3labs/mcp-go │ +680 │ +34 │ +11 │ MIT │ Go SDK for building MCP servers + +Star velocity = net new stars in the past 30 days. +``` + +High star velocity with low contributor growth may indicate hype without sustained community investment. Look for projects where contributor count grows proportionally to stars — that signals genuine adoption, not just visibility. + +## Audit Mode + +Audit mode checks your existing dependencies for updates, license changes, and maintenance risks. Run it regularly to catch supply chain issues before they become vulnerabilities. + +### Audit Your Dependencies + +1. Run the scout command with the `--audit` flag and point it at your dependency manifest: + +```bash +/scout --audit go.mod +``` + +2. Pinkman reads your `go.mod` (or `package.json`, `Cargo.toml`, `pyproject.toml`) and checks each dependency against its upstream repository. + +3. Review the findings. Pinkman flags four categories of risk: outdated versions, license changes since your pinned version, unmaintained projects, and known vulnerabilities. + +### Example Output + +``` +🔎 Auditing: go.mod (14 direct dependencies) + + Status │ Dependency │ Pinned │ Latest │ Issue + ⚠ OLD │ github.com/spf13/cobra │ v1.8.0 │ v1.9.1 │ 3 minor versions behind + ❌ LIC │ github.com/example/lib │ v2.1.0 │ v3.0.0 │ License changed: MIT → BSL-1.1 + ⚠ MAINT│ github.com/old/tool │ v0.4.2 │ v0.4.2 │ No commits in 18 months + ✅ OK │ golang.org/x/text │ v0.16.0 │ v0.16.0 │ Up to date + +Summary: 1 license change (action required), 1 outdated, 1 unmaintained, 11 healthy. +``` + +The `❌ LIC` flag demands immediate attention. A license change from MIT to BSL-1.1 means the upstream project switched to a source-available license. Pin your current version and evaluate whether the new license terms are acceptable before upgrading. + +## Report Mode + +Report mode generates a structured adoption recommendation for a single project. Use it when you have narrowed your candidates and need a thorough evaluation before committing. + +### Generate an Adoption Report + +1. Run the scout command with the `--report` flag and a repository URL: + +```bash +/scout --report https://github.com/example/project +``` + +2. Pinkman clones the repository metadata (not the full source), analyzes its README, license, dependency tree, CI configuration, release cadence, and contributor distribution. + +3. Review the structured report. It follows a consistent format designed for decision-making. + +### Example Report Structure + +``` +📋 Adoption Report: example/project +Generated: 2026-08-23 + +## Identity +- Name: project +- License: Apache-2.0 (✅ compatible) +- Language: Go (98.2%) +- Latest release: v2.4.1 (2026-08-10) + +## Maintenance Health +- Commits (90 days): 147 +- Open issues: 23 (avg response: 2.1 days) +- Open PRs: 4 (avg merge time: 3.8 days) +- Contributors (90 days): 12 +- Bus factor: 3 (top 3 contributors = 72% of commits) +- CI: GitHub Actions (passing) + +## Dependency Profile +- Direct dependencies: 8 +- Transitive dependencies: 34 +- Overlap with your project: 6 shared deps +- Known vulnerabilities: 0 + +## Release Cadence +- Releases (12 months): 11 +- Avg time between releases: 33 days +- Follows semver: Yes + +## Recommendation +- Verdict: ✅ ADOPT +- Confidence: HIGH +- Rationale: Active maintenance, compatible license, low dependency + footprint, consistent release cadence, healthy bus factor. +- Risks: None identified. +``` + +The bus factor metric counts how many top contributors account for the majority of recent commits. A bus factor of 1 means a single maintainer — high risk for long-term adoption. A bus factor of 3 or higher indicates distributed ownership. + +## Persistent Reports + +Pinkman saves every report to disk for future reference. You do not need to re-run evaluations to recall past results. + +### Finding Saved Reports + +1. Navigate to the `.uf/pinkman/reports/` directory in your project root. Pinkman creates this directory automatically on the first `/scout --report` invocation. + +2. Reports are saved as Markdown files named by project and date: + +``` +.uf/pinkman/reports/ +├── example-project-2026-08-23.md +├── mark3labs-mcp-go-2026-08-15.md +└── spf13-cobra-2026-08-01.md +``` + +3. Open any report file to review the full evaluation. The format matches the terminal output, so you can share reports in pull requests or architecture decision records without reformatting. + +4. Pinkman appends an update log to existing reports when you re-evaluate the same project. This creates a historical record of how a dependency's health changes over time. + +## Dewey Integration + +When Dewey is running, Pinkman stores every evaluation as a semantic learning. This transforms `/scout` from a stateless tool into a knowledge-building system. + +### How Past Evaluations Inform Future Scouting + +1. **Automatic recall**: When you run `/scout` for a topic you have evaluated before, Pinkman queries Dewey for prior learnings. If you evaluated MCP servers last month, a new `/scout --trend MCP servers` command surfaces those earlier findings alongside fresh data. You see what changed without re-reading old reports. + +2. **Cross-project context**: Dewey indexes learnings across all your projects. If you evaluated `spf13/cobra` in Project A, that evaluation is available when you scout dependencies in Project B. Pinkman tells you: "Previously evaluated in project-a on 2026-08-01 — verdict: ADOPT (HIGH confidence)." + +3. **License pattern detection**: Over time, Pinkman builds a map of license changes across your dependency graph. If a maintainer has changed licenses on previous projects, Pinkman flags this pattern when you evaluate their new projects. This early warning helps you avoid dependencies with unstable licensing. + +4. **Contradiction resolution**: When a project's health metrics change between evaluations (e.g., maintenance score dropped from healthy to unmaintained), Dewey's compilation step resolves the contradiction temporally. The compiled article reflects the current state while preserving the history, so you can trace when and why a dependency's status changed. + +Start Dewey with `dewey serve` before your scouting session to enable this integration. Without Dewey, `/scout` still works — you just lose cross-session memory and must rely on the local report files in `.uf/pinkman/reports/`. From 0e1ae567aaba057764196db771b60d395fd5f8e1 Mon Sep 17 00:00:00 2001 From: Jay Flowers Date: Sun, 23 Aug 2026 19:58:30 -0400 Subject: [PATCH 3/7] =?UTF-8?q?fix:=20address=20code=20review=20findings?= =?UTF-8?q?=20=E2=80=94=20remove=20pinkman=20tutorial,=20fix=20cross-refs,?= =?UTF-8?q?=20align=20schemas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove pinkman-oss-scout.md tutorial per user direction - Fix dead cross-references in dewey-knowledge-stores blog (correct slugs) - Fix dead link in dewey-knowledge-stores tutorial (/docs/projects/dewey/) - SHA-pin GitHub Actions in gaze-baseline-comparison blog - Add missing code block language IDs (FT-001) across 5 files - Fix Constitution Principle III name (Observable Quality, not Actionable Output) - Align pluggable-llm-providers blog with tutorial (vertexai, claude model, config path) - Add blog↔tutorial cross-links in both directions - Align knowledge stores YAML schema between blog and tutorial - Standardize gaze CLI flag to --format=json - Fix MCP tool call syntax labels in dewey-knowledge-stores tutorial - Add explicit tutorial list to _index.md - Add Further Reading sections to all tutorials - Update ci-failure-classification CTA with specific link --- content/blog/ci-failure-classification.md | 4 +- content/blog/dewey-knowledge-stores.md | 41 ++- content/blog/dewey-slash-command-ux.md | 14 +- content/blog/gaze-baseline-comparison.md | 14 +- content/blog/pluggable-llm-providers.md | 48 ++-- content/docs/tutorials/_index.md | 9 +- .../docs/tutorials/dewey-knowledge-stores.md | 19 +- .../tutorials/dewey-provider-configuration.md | 6 + .../docs/tutorials/gaze-crap-baseline-ci.md | 5 + .../docs/tutorials/onboard-customization.md | 5 + content/docs/tutorials/pinkman-oss-scout.md | 234 ------------------ .../changes/blog-tutorials-batch/tasks.md | 2 +- 12 files changed, 94 insertions(+), 307 deletions(-) delete mode 100644 content/docs/tutorials/pinkman-oss-scout.md diff --git a/content/blog/ci-failure-classification.md b/content/blog/ci-failure-classification.md index 8f157ef..fd4c81d 100644 --- a/content/blog/ci-failure-classification.md +++ b/content/blog/ci-failure-classification.md @@ -26,7 +26,7 @@ The `/review-pr` command takes a different approach. Instead of dumping a wall o The classification works by comparing the failure against the base branch. If a test also fails on main, it's pre-existing — not your regression. If a lint violation exists in files you didn't touch, it's pre-existing. If a check fails only on your branch, in code your commits modified, it's PR-caused and needs your attention. -``` +```text /review-pr ``` @@ -63,4 +63,4 @@ Every minute spent investigating a pre-existing CI failure is a minute not spent The pattern is straightforward. Run one command after creating your PR. Get a classified report that separates your regressions from inherited problems. Fix what's yours, forward what isn't, and move on. -If your team loses hours per week to CI forensics, try `/review-pr` on your next pull request. Check the [Unbound Force documentation](/docs/getting-started/) to get started, or explore the [review-pr command source](https://github.com/unbound-force/unbound-force) to see how causality classification works under the hood. +If your team loses hours per week to CI forensics, try `/review-pr` on your next pull request. Run `/review-pr` after creating a PR to get a classified report that separates your regressions from inherited problems. See the [Quick Start guide](/docs/getting-started/quick-start/) for installation, or explore the [Unbound Force repository](https://github.com/unbound-force/unbound-force) to see how causality classification works under the hood. diff --git a/content/blog/dewey-knowledge-stores.md b/content/blog/dewey-knowledge-stores.md index a1378f1..584f5e5 100644 --- a/content/blog/dewey-knowledge-stores.md +++ b/content/blog/dewey-knowledge-stores.md @@ -18,7 +18,7 @@ AI agents accumulate knowledge across sessions. Decisions made during code revie The loss of structured knowledge is only half the problem. Organizations generate vast amounts of unstructured content — meeting notes, Slack exports, GitHub discussions, design documents — that contain critical decisions and patterns buried in prose. No agent can extract those insights without reading every document, every time. The knowledge exists, but it's locked inside formats that resist automated extraction. -This is the third post in our Dewey blog arc. In [The Librarian vs The Index](/blog/dewey-librarian-vs-index/), we explored why semantic search alone isn't enough. In [How Dewey Became a Knowledge Curator](/blog/dewey-knowledge-curator/), we showed how Dewey moved beyond retrieval into active knowledge management. Now we tackle the two remaining gaps: durability and automated extraction. +This is the third post in our Dewey blog arc. In [The Librarian vs The Index](/blog/dewey-vs-karpathy/), we explored why semantic search alone isn't enough. In [How Dewey Became a Knowledge Curator](/blog/dewey-curator/), we showed how Dewey moved beyond retrieval into active knowledge management. Now we tackle the two remaining gaps: durability and automated extraction. ## Two Complementary Solutions @@ -48,34 +48,27 @@ A `knowledge-stores.yaml` file defines which indexed sources feed into which sto ```yaml stores: - architecture-decisions: + - name: architecture-decisions description: "Architectural decisions from design docs and discussions" sources: - - id: github-discussions - filter: "label:architecture" - - id: design-docs - path: "docs/architecture/**/*.md" - extraction: - categories: - - decision - - pattern - - constraint - min_confidence: 0.7 - - operational-runbooks: + - github-discussions + - design-docs + settings: + min_confidence: high + extract_decisions: true + extract_patterns: true + + - name: operational-runbooks description: "Operational patterns from incident reports and postmortems" sources: - - id: incident-reports - path: "docs/incidents/**/*.md" - extraction: - categories: - - pattern - - gotcha - - procedure - min_confidence: 0.6 + - incident-reports + settings: + min_confidence: medium + extract_decisions: false + extract_patterns: true ``` -Each store targets a specific knowledge domain. The `sources` field maps to Dewey's indexed content — the same sources you configure in `.uf/dewey/sources.yaml`. The `extraction` block controls what the LLM looks for and the minimum confidence threshold for inclusion. +Each store targets a specific knowledge domain. The `sources` field references source IDs from your `sources.yaml` — the same sources you configure for Dewey's index. The `settings` block controls extraction behavior and the minimum confidence threshold for inclusion. ### Step 2: Run Curation @@ -154,7 +147,7 @@ The combination of file-backed persistence and curated extraction differs from t |-----------|-------------|--------------| | Knowledge quality | Retrieves fragments without quality assessment | Extracts with confidence scoring and quality flags | | Provenance | Chunk ID, sometimes source file | Full source traceability to specific documents and excerpts | -| Trust model | All retrieved content treated equally | 4-tier trust system (authored → curated → draft → untrusted) | +| Trust model | All retrieved content treated equally | 5-tier trust system (authored → validated → curated → draft → untrusted) | | Data locality | Usually cloud-hosted vector DB | Local-only (SQLite + Ollama) | | Durability | Database is the single source of truth | File-backed dual-write survives database deletion | | Portability | Tied to the vector DB instance | Git-compatible files travel with the repository | diff --git a/content/blog/dewey-slash-command-ux.md b/content/blog/dewey-slash-command-ux.md index 46e90fc..77e1433 100644 --- a/content/blog/dewey-slash-command-ux.md +++ b/content/blog/dewey-slash-command-ux.md @@ -34,7 +34,7 @@ The slash command file acts as a decision tree. When a user invokes `/dewey-stor Power users who know their tag taxonomy and category system can bypass all guidance. They provide everything upfront, and the agent executes without negotiation. -``` +```text /dewey-store --tag auth-design --category decision We decided to use short-lived JWTs with a 15-minute expiry @@ -48,7 +48,7 @@ The agent calls `store_learning` with the exact tag and category provided. No su The most common mode. The user provides content but no metadata. The agent analyzes the content and proposes tags ranked by specificity, plus a category based on content patterns. -``` +```text /dewey-store We tried using WebSockets for the real-time dashboard but @@ -60,7 +60,7 @@ operational complexity dropped significantly. The agent responds with ranked suggestions: -``` +```text Proposed tag (ranked by specificity): 1. sse-migration — matches the specific technology switch 2. real-time-dashboard — matches the feature context @@ -79,7 +79,7 @@ The ranking by specificity matters. Generic tags like "infrastructure" appear la The highest-value mode for meeting transcripts, Slack threads, and design discussions. The user pastes a long conversation, and the agent breaks it into multiple distinct learnings, each with its own tag and category proposal. -``` +```text /dewey-store --extract [Pasted Slack thread about authentication redesign, 47 messages] @@ -87,7 +87,7 @@ The highest-value mode for meeting transcripts, Slack threads, and design discus The agent identifies distinct knowledge units and presents them individually: -``` +```text Extracted 4 learnings from this thread: Learning 1/4: @@ -129,7 +129,7 @@ Each learning gets individual review. The user can store all four, edit specific **Before `/dewey-store`**: The developer pastes a Slack thread and says "remember this." The agent calls `store_learning` once with `tag: "auth"` and `category: "context"`. One monolithic entry. Unfindable in six months. -```go +```text // What the agent did before store_learning({ information: "[entire 47-message Slack thread pasted verbatim]", @@ -141,7 +141,7 @@ store_learning({ **After `/dewey-store`**: The same thread produces four distinct learnings. Each has a specific tag that matches its content. Each has a category that reflects whether it's a decision, a gotcha, or background context. Each is individually reviewable before storage. -```go +```text // What the agent does now store_learning({ information: "JWT refresh tokens must be opaque...", diff --git a/content/blog/gaze-baseline-comparison.md b/content/blog/gaze-baseline-comparison.md index c252eee..b53738c 100644 --- a/content/blog/gaze-baseline-comparison.md +++ b/content/blog/gaze-baseline-comparison.md @@ -25,7 +25,7 @@ Gaze now handles baseline comparison natively. The design follows a convention-o Generating the initial baseline is a single command: ```bash -gaze crap --json > .gaze/baseline.json +gaze crap --format=json > .gaze/baseline.json ``` Commit that file to your repository. On subsequent runs, `gaze crap` detects `.gaze/baseline.json`, loads it, and compares every function in the current run against the baseline. Each function receives a classification: @@ -104,9 +104,9 @@ jobs: crap-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: actions/setup-go@v5 + - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 with: go-version: "1.23" @@ -127,16 +127,16 @@ No wrapper scripts. No reusable workflow dependency. No post-processing step to To update the baseline after intentional changes (refactoring that temporarily increases a score, or accepting a justified complexity increase), regenerate and commit: ```bash -gaze crap --json > .gaze/baseline.json +gaze crap --format=json > .gaze/baseline.json git add .gaze/baseline.json git commit -m "chore: update CRAP baseline" ``` ## Constitution Alignment -This feature directly fulfills Principle III (Actionable Output) from the Unbound Force constitution. Principle III requires that tool output be comparable across runs — a single-run CRAP report is informative, but it cannot answer the question "did this change make things worse?" without a reference point. Baseline comparison closes that gap by making cross-run comparability a native capability rather than an external integration concern. +This feature directly fulfills Principle III (Observable Quality) from the Unbound Force constitution. Principle III requires that tool output be comparable across runs — a single-run CRAP report is informative, but it cannot answer the question "did this change make things worse?" without a reference point. Baseline comparison closes that gap by making cross-run comparability a native capability rather than an external integration concern. -The classification model (regression, improvement, new, removed) also satisfies the actionability requirement. Each classification maps to a concrete action: regressions must be fixed, improvements validate refactoring effort, new functions are evaluated against the threshold, and removed functions confirm cleanup. No classification leaves the engineer wondering "what do I do with this information?" +The classification model (regression, improvement, new, removed) also satisfies the observability requirement. Each classification maps to a concrete action: regressions must be fixed, improvements validate refactoring effort, new functions are evaluated against the threshold, and removed functions confirm cleanup. No classification leaves the engineer wondering "what do I do with this information?" ## Try It @@ -147,7 +147,7 @@ Install Gaze and generate your first baseline: ```bash go install github.com/unbound-force/gaze/cmd/gaze@latest go test -coverprofile=coverage.out ./... -gaze crap --json > .gaze/baseline.json +gaze crap --format=json > .gaze/baseline.json git add .gaze/baseline.json git commit -m "chore: add CRAP baseline" ``` diff --git a/content/blog/pluggable-llm-providers.md b/content/blog/pluggable-llm-providers.md index 108869b..5f79a75 100644 --- a/content/blog/pluggable-llm-providers.md +++ b/content/blog/pluggable-llm-providers.md @@ -22,7 +22,7 @@ The original architecture forced an all-or-nothing choice. You ran everything lo ## Pluggable Provider Interfaces -The `016-pluggable-providers` branch introduces two provider interfaces — `Embedder` and `Synthesizer` — that decouple Dewey's intelligence layer from any specific LLM backend. Each interface has exactly one job: `Embedder` converts text into vector embeddings for semantic search, and `Synthesizer` generates natural language output for knowledge compilation. +Dewey introduces two provider interfaces — `Embedder` and `Synthesizer` — that decouple Dewey's intelligence layer from any specific LLM backend. Each interface has exactly one job: `Embedder` converts text into vector embeddings for semantic search, and `Synthesizer` generates natural language output for knowledge compilation. Factory functions `NewEmbedderFromConfig()` and `NewSynthesizerFromConfig()` centralize provider construction. They read the configuration, select the correct backend, and return a ready-to-use provider. Callers never import provider-specific packages directly. Adding a new backend — Anthropic, OpenAI, a future local model — means implementing the interface and registering it in the factory. No call sites change. @@ -36,19 +36,19 @@ Ollama remains the zero-config default. If you install Dewey and do nothing else ## Configuration: Two New Fields -Two new fields in Dewey's configuration control provider selection: `embedding.provider` and `synthesis.provider`. Each accepts `ollama` or `vertex-ai` as values. +Two new fields in Dewey's configuration control provider selection: `embedding.provider` and `synthesis.provider`. Each accepts `ollama` or `vertexai` as values. ```yaml -# Per-vault config: .dewey/config.yaml +# Per-vault config: config.yaml (in Dewey vault directory) embedding: provider: ollama model: nomic-embed-text synthesis: - provider: vertex-ai - model: gemini-2.5-flash - project: my-gcp-project - location: us-central1 + provider: vertexai + model: claude-sonnet-4-20250514 + project: your-project-id + location: us-east5 ``` For teams running multiple vaults, a global configuration file at `~/.config/dewey/config.yaml` sets defaults that individual vaults can override. This prevents duplicating Vertex AI credentials across every project. The vault-level config takes precedence when both exist. @@ -56,10 +56,10 @@ For teams running multiple vaults, a global configuration file at `~/.config/dew ```yaml # Global config: ~/.config/dewey/config.yaml synthesis: - provider: vertex-ai - model: gemini-2.5-flash - project: my-gcp-project - location: us-central1 + provider: vertexai + model: claude-sonnet-4-20250514 + project: your-project-id + location: us-east5 ``` ### Config Precedence: A Deliberate Asymmetry @@ -89,15 +89,15 @@ embedding: model: nomic-embed-text synthesis: - provider: vertex-ai - model: gemini-2.5-flash - project: my-gcp-project - location: us-central1 + provider: vertexai + model: claude-sonnet-4-20250514 + project: your-project-id + location: us-east5 ``` -This combination plays to each provider's strengths. Ollama's `nomic-embed-text` produces high-quality embeddings with low latency on commodity hardware — no GPU required for the embedding model. Vertex AI's Gemini models handle the heavy reasoning that knowledge compilation demands. Your raw data stays local for indexing and search; only the synthesis prompts (which contain aggregated, anonymized learnings) leave the machine. +This combination plays to each provider's strengths. Ollama's `nomic-embed-text` produces high-quality embeddings with low latency on commodity hardware — no GPU required for the embedding model. Vertex AI's Claude models handle the heavy reasoning that knowledge compilation demands. Your raw data stays local for indexing and search; only the synthesis prompts (which contain aggregated, anonymized learnings) leave the machine. -Teams that need full data sovereignty can set both providers to `ollama` and accept the synthesis quality trade-off. Teams that want maximum quality can set both to `vertex-ai`. The pluggable architecture makes this a configuration decision, not a code change. +Teams that need full data sovereignty can set both providers to `ollama` and accept the synthesis quality trade-off. Teams that want maximum quality can set both to `vertexai`. The pluggable architecture makes this a configuration decision, not a code change. ## Closing the Compilation Loop: `store_compiled` @@ -110,7 +110,7 @@ With `store_compiled`, the workflow becomes a closed loop: 3. Agent calls `dewey_store_compiled` with the synthesized article, source learnings, and topic tag 4. Dewey persists the compiled article with full provenance metadata -``` +```text compile → synthesize → store_compiled → searchable knowledge ``` @@ -126,7 +126,7 @@ Constitutional amendments in the Unbound Force ecosystem are not taken lightly. ## Get Started -Upgrade to the latest Dewey build from the `016-pluggable-providers` branch: +Install or upgrade Dewey to the latest release: ```bash go install github.com/unbound-force/dewey/cmd/dewey@latest @@ -139,15 +139,17 @@ To add Vertex AI synthesis to an existing vault: gcloud auth application-default login # Add synthesis config to your vault -cat >> .dewey/config.yaml << 'EOF' +cat >> config.yaml << 'EOF' synthesis: - provider: vertex-ai - model: gemini-2.5-flash + provider: vertexai + model: claude-sonnet-4-20250514 project: YOUR_PROJECT - location: us-central1 + location: us-east5 EOF ``` +For a detailed walkthrough of provider configuration, follow the companion tutorial: [Configuring Dewey Embedding and Synthesis Providers](/docs/tutorials/dewey-provider-configuration/). + Run `dewey_compile` through your MCP client to test the synthesis quality difference. Compare the output against a pure Ollama compilation of the same learnings. The difference in reasoning depth is the reason this architecture exists. For questions, issues, or provider requests, open an issue on the [Dewey repository](https://github.com/unbound-force/dewey). diff --git a/content/docs/tutorials/_index.md b/content/docs/tutorials/_index.md index efbd97d..420e8d0 100644 --- a/content/docs/tutorials/_index.md +++ b/content/docs/tutorials/_index.md @@ -1,6 +1,6 @@ --- title: "Tutorials" -description: "Step-by-step guides for setting up and using Unbound Force tools — Dewey knowledge stores, Gaze CI integration, Pinkman scout, and more." +description: "Step-by-step guides for setting up and using Unbound Force tools — Dewey knowledge stores, Gaze CI integration, onboarding customization, and more." lead: "Hands-on guides that walk you through setup, configuration, and daily usage of the Unbound Force toolchain." date: 2026-08-23T00:00:00+00:00 draft: false @@ -10,4 +10,9 @@ toc: false ## Available Tutorials -Browse the tutorials below to get started with specific tools and workflows. Each guide includes prerequisites, setup instructions, and verification steps. +Each guide includes prerequisites, setup instructions, and verification steps. + +- [Setting Up Dewey Knowledge Stores](/docs/tutorials/dewey-knowledge-stores/) — configure automated knowledge extraction from indexed sources +- [Configuring Dewey Providers](/docs/tutorials/dewey-provider-configuration/) — switch between local Ollama and cloud Vertex AI for embeddings and synthesis +- [CRAP Baseline Comparison in CI](/docs/tutorials/gaze-crap-baseline-ci/) — detect per-function CRAP score regressions on every PR +- [Customizing Your Hero Experience with /onboard](/docs/tutorials/onboard-customization/) — capture your preferences so heroes adapt to your working style diff --git a/content/docs/tutorials/dewey-knowledge-stores.md b/content/docs/tutorials/dewey-knowledge-stores.md index 8c48000..f0ebf7e 100644 --- a/content/docs/tutorials/dewey-knowledge-stores.md +++ b/content/docs/tutorials/dewey-knowledge-stores.md @@ -32,7 +32,7 @@ Before configuring knowledge stores, verify that you have the following tools in dewey index # Index all configured sources ``` - If you have not configured any sources yet, see the [Dewey Getting Started guide](/docs/getting-started/dewey/) before continuing. + If you have not configured any sources yet, see the [Dewey project documentation](/docs/projects/dewey/) for setup instructions before continuing. ## Creating a Knowledge Store @@ -171,9 +171,9 @@ Once curation completes, curated knowledge is searchable through Dewey's semanti ### Search curated content only -Use the `tier` filter to restrict results to curated knowledge: +Use the `tier` filter to restrict results to curated knowledge. Run this MCP tool call in your AI agent session: -```bash +```text dewey_semantic_search_filtered(query: "authentication flow", tier: "curated") ``` @@ -191,9 +191,9 @@ Dewey organizes content into trust tiers. Each tier represents a different level | `draft` | Raw learnings stored via `dewey_store_learning` before compilation | Work-in-progress insights | | `untrusted` | Unverified external content | Background research, third-party docs | -Search a specific tier: +Search a specific tier (MCP tool calls, run in your AI agent session): -```bash +```text dewey_semantic_search_filtered(query: "deployment strategy", tier: "authored") dewey_semantic_search_filtered(query: "deployment strategy", tier: "curated") dewey_semantic_search_filtered(query: "deployment strategy", tier: "draft") @@ -319,10 +319,15 @@ Extract mode identifies the most important decisions, patterns, and action items ### Verifying stored knowledge -After storing ad-hoc knowledge, verify it appears in search results: +After storing ad-hoc knowledge, verify it appears in search results (MCP tool call, run in your AI agent session): -```bash +```text dewey_semantic_search(query: "JWT authentication") ``` Stored learnings are immediately searchable. They start in the `draft` tier and move to `validated` after human review via `dewey promote`. + +## Further Reading + +- [Your AI Agent's Memory Survives Database Deletion](/blog/dewey-knowledge-stores/) — the design rationale behind file-backed learnings and curated knowledge stores +- [Dewey](/docs/projects/dewey/) — project overview, installation, and architecture diff --git a/content/docs/tutorials/dewey-provider-configuration.md b/content/docs/tutorials/dewey-provider-configuration.md index a7533c5..00286da 100644 --- a/content/docs/tutorials/dewey-provider-configuration.md +++ b/content/docs/tutorials/dewey-provider-configuration.md @@ -283,3 +283,9 @@ dewey reindex ``` This drops all existing embeddings and regenerates them with the new model. The operation is safe — it does not modify your vault content, only the derived vector index. + +## Further Reading + +- [Pluggable LLM Providers](/blog/pluggable-llm-providers/) — the design rationale behind the Embedder and Synthesizer interfaces +- [Setting Up Dewey Knowledge Stores](/docs/tutorials/dewey-knowledge-stores/) — configure automated knowledge extraction from indexed sources +- [Dewey](/docs/projects/dewey/) — project overview, installation, and architecture diff --git a/content/docs/tutorials/gaze-crap-baseline-ci.md b/content/docs/tutorials/gaze-crap-baseline-ci.md index 3ccab93..f001cff 100644 --- a/content/docs/tutorials/gaze-crap-baseline-ci.md +++ b/content/docs/tutorials/gaze-crap-baseline-ci.md @@ -198,3 +198,8 @@ Do not refresh the baseline on every PR. The baseline should change deliberately **Cause**: gaze identifies functions by their fully qualified name (`package.Function`). A rename creates a new identity that has no baseline entry. **Fix**: Refresh the baseline after renaming functions. If you rename functions frequently during a refactoring PR, refresh the baseline in a preparatory commit on `main` before opening the refactoring PR. + +## Further Reading + +- [Your CI Just Got Smarter](/blog/gaze-baseline-comparison/) — the design rationale behind convention-over-configuration baseline comparison +- [Gaze](/docs/projects/gaze/) — project overview, metrics, and architecture diff --git a/content/docs/tutorials/onboard-customization.md b/content/docs/tutorials/onboard-customization.md index 856ed3e..0748bc8 100644 --- a/content/docs/tutorials/onboard-customization.md +++ b/content/docs/tutorials/onboard-customization.md @@ -310,3 +310,8 @@ A **draft** profile has `status: draft` and is missing one or more interview pha A **complete** profile has `status: complete` and all three phases finished. Heroes read complete profiles without additional questions. Complete profiles produce the most consistent hero behavior because every hero has the full context from the start. Upgrade a draft to complete by running `/onboard` and finishing the remaining phases. The status field updates automatically when all three phases are present. + +## Further Reading + +- [The Team](/docs/team/) — meet the five heroes and understand their roles +- [Getting Started](/docs/getting-started/) — installation, setup, and common workflows diff --git a/content/docs/tutorials/pinkman-oss-scout.md b/content/docs/tutorials/pinkman-oss-scout.md deleted file mode 100644 index 6d19b47..0000000 --- a/content/docs/tutorials/pinkman-oss-scout.md +++ /dev/null @@ -1,234 +0,0 @@ ---- -title: "Getting Started with Pinkman OSS Scout" -description: "Step-by-step tutorial for using Pinkman's /scout command to discover, evaluate, audit, and report on open source projects for adoption." -lead: "Evaluate open source projects before adopting them. /scout gives you license compatibility, maintenance health, dependency analysis, and structured adoption recommendations." -date: 2026-08-23T00:00:00+00:00 -draft: false -weight: 40 -toc: true ---- - -## Prerequisites - -Before using `/scout`, complete these setup steps: - -1. Run `uf init` in your project root. This scaffolds the `pinkman.md` agent file alongside your other Unbound Force agents. Pinkman handles open source intelligence — license analysis, maintenance health checks, and adoption recommendations. - -2. Start Dewey if you want cross-session memory. Dewey is optional but recommended. When running, Pinkman stores every evaluation as a learning, so future scouting sessions draw on past analysis instead of starting from scratch. - -3. Verify Pinkman is available by checking that `.opencode/agents/pinkman.md` exists in your project. The agent activates automatically when you invoke any `/scout` command. - -## Discover Mode - -Discover mode is the default. Use it to find open source projects by keyword, filtered for license compatibility with your project. - -### Find Projects by Keyword - -1. Run the scout command with a topic: - -```bash -/scout static analysis Go -``` - -2. Pinkman searches GitHub for projects matching your query. It filters results against your project's license (detected from `LICENSE` or `go.mod`) and returns a ranked list. - -3. Review the output. Each result includes the project name, license verdict, star count, last commit date, and a one-line summary of what the project does. - -### Example Output - -``` -🔍 Scouting: "static analysis Go" -License context: Apache-2.0 (from LICENSE) - - # │ Project │ License │ Compat │ Stars │ Last Commit │ Summary - 1 │ golangci/golangci-lint │ GPL-3.0 │ ⚠ WEAK │ 15.2k│ 2 days ago │ Fast Go linters runner - 2 │ dominikh/go-tools │ MIT │ ✅ OK │ 6.1k │ 5 days ago │ Staticcheck and related tools - 3 │ mgechev/revive │ MIT │ ✅ OK │ 4.8k │ 1 week ago │ Extensible Go linter framework - 4 │ securego/gosec │ Apache-2.0 │ ✅ OK │ 7.6k │ 3 days ago │ Security-focused Go source scanner - -Found 4 projects. Use /scout --report for a full evaluation. -``` - -Pinkman marks GPL-3.0 as `⚠ WEAK` compatibility when your project uses Apache-2.0. This does not mean you cannot use the project — it means you need to evaluate the integration boundary (binary vs. library linking) before adopting it. - -## Understanding Results - -### License Verdicts and Compatibility Tiers - -Pinkman classifies license compatibility into three tiers: - -- **✅ OK** — The dependency's license is fully compatible with your project's license. No restrictions on how you integrate it. -- **⚠ WEAK** — The dependency's license imposes conditions that may conflict with your project's license. Review the specific terms before adopting. Common examples: GPL libraries used in Apache-2.0 projects, or AGPL services called over the network. -- **❌ BLOCK** — The dependency's license is incompatible with your project's license. Adopting it would require relicensing your project or isolating the dependency behind a process boundary. - -### Dependency Lists and Overlap Tables - -When Pinkman evaluates multiple projects in the same session, it generates an overlap table. This table shows shared transitive dependencies across candidates. High overlap means adopting multiple projects adds minimal dependency weight. Low overlap means each project brings its own dependency tree, increasing your supply chain surface area. - -``` -Dependency Overlap (2 of 4 candidates share deps): - - Dependency │ golangci-lint │ revive │ gosec - golang.org/x/tools │ ✓ │ ✓ │ ✓ - golang.org/x/mod │ ✓ │ ✓ │ ✗ - github.com/fatih/color│ ✓ │ ✗ │ ✗ -``` - -Use this table to minimize the number of new transitive dependencies your project takes on. - -## Trend Mode - -Trend mode identifies projects gaining momentum. Use it to spot emerging tools before they become mainstream. - -### Identify Trending Projects - -1. Run the scout command with the `--trend` flag: - -```bash -/scout --trend MCP servers -``` - -2. Pinkman queries GitHub's trending data and cross-references it with star velocity, fork rate, and contributor growth over the past 30 days. - -3. Review the quantitative indicators. Each result includes growth metrics alongside the standard project metadata. - -### Example Output - -``` -📈 Trending: "MCP servers" (30-day window) - - # │ Project │ ⭐ Velocity │ 🍴 Forks/mo │ 👥 New Contributors │ License │ Summary - 1 │ modelcontextprotocol/servers │ +2,340 │ +187 │ +42 │ MIT │ Reference MCP server implementations - 2 │ punkpeye/awesome-mcp-servers │ +1,890 │ +95 │ +18 │ CC0-1.0 │ Curated list of MCP servers - 3 │ mark3labs/mcp-go │ +680 │ +34 │ +11 │ MIT │ Go SDK for building MCP servers - -Star velocity = net new stars in the past 30 days. -``` - -High star velocity with low contributor growth may indicate hype without sustained community investment. Look for projects where contributor count grows proportionally to stars — that signals genuine adoption, not just visibility. - -## Audit Mode - -Audit mode checks your existing dependencies for updates, license changes, and maintenance risks. Run it regularly to catch supply chain issues before they become vulnerabilities. - -### Audit Your Dependencies - -1. Run the scout command with the `--audit` flag and point it at your dependency manifest: - -```bash -/scout --audit go.mod -``` - -2. Pinkman reads your `go.mod` (or `package.json`, `Cargo.toml`, `pyproject.toml`) and checks each dependency against its upstream repository. - -3. Review the findings. Pinkman flags four categories of risk: outdated versions, license changes since your pinned version, unmaintained projects, and known vulnerabilities. - -### Example Output - -``` -🔎 Auditing: go.mod (14 direct dependencies) - - Status │ Dependency │ Pinned │ Latest │ Issue - ⚠ OLD │ github.com/spf13/cobra │ v1.8.0 │ v1.9.1 │ 3 minor versions behind - ❌ LIC │ github.com/example/lib │ v2.1.0 │ v3.0.0 │ License changed: MIT → BSL-1.1 - ⚠ MAINT│ github.com/old/tool │ v0.4.2 │ v0.4.2 │ No commits in 18 months - ✅ OK │ golang.org/x/text │ v0.16.0 │ v0.16.0 │ Up to date - -Summary: 1 license change (action required), 1 outdated, 1 unmaintained, 11 healthy. -``` - -The `❌ LIC` flag demands immediate attention. A license change from MIT to BSL-1.1 means the upstream project switched to a source-available license. Pin your current version and evaluate whether the new license terms are acceptable before upgrading. - -## Report Mode - -Report mode generates a structured adoption recommendation for a single project. Use it when you have narrowed your candidates and need a thorough evaluation before committing. - -### Generate an Adoption Report - -1. Run the scout command with the `--report` flag and a repository URL: - -```bash -/scout --report https://github.com/example/project -``` - -2. Pinkman clones the repository metadata (not the full source), analyzes its README, license, dependency tree, CI configuration, release cadence, and contributor distribution. - -3. Review the structured report. It follows a consistent format designed for decision-making. - -### Example Report Structure - -``` -📋 Adoption Report: example/project -Generated: 2026-08-23 - -## Identity -- Name: project -- License: Apache-2.0 (✅ compatible) -- Language: Go (98.2%) -- Latest release: v2.4.1 (2026-08-10) - -## Maintenance Health -- Commits (90 days): 147 -- Open issues: 23 (avg response: 2.1 days) -- Open PRs: 4 (avg merge time: 3.8 days) -- Contributors (90 days): 12 -- Bus factor: 3 (top 3 contributors = 72% of commits) -- CI: GitHub Actions (passing) - -## Dependency Profile -- Direct dependencies: 8 -- Transitive dependencies: 34 -- Overlap with your project: 6 shared deps -- Known vulnerabilities: 0 - -## Release Cadence -- Releases (12 months): 11 -- Avg time between releases: 33 days -- Follows semver: Yes - -## Recommendation -- Verdict: ✅ ADOPT -- Confidence: HIGH -- Rationale: Active maintenance, compatible license, low dependency - footprint, consistent release cadence, healthy bus factor. -- Risks: None identified. -``` - -The bus factor metric counts how many top contributors account for the majority of recent commits. A bus factor of 1 means a single maintainer — high risk for long-term adoption. A bus factor of 3 or higher indicates distributed ownership. - -## Persistent Reports - -Pinkman saves every report to disk for future reference. You do not need to re-run evaluations to recall past results. - -### Finding Saved Reports - -1. Navigate to the `.uf/pinkman/reports/` directory in your project root. Pinkman creates this directory automatically on the first `/scout --report` invocation. - -2. Reports are saved as Markdown files named by project and date: - -``` -.uf/pinkman/reports/ -├── example-project-2026-08-23.md -├── mark3labs-mcp-go-2026-08-15.md -└── spf13-cobra-2026-08-01.md -``` - -3. Open any report file to review the full evaluation. The format matches the terminal output, so you can share reports in pull requests or architecture decision records without reformatting. - -4. Pinkman appends an update log to existing reports when you re-evaluate the same project. This creates a historical record of how a dependency's health changes over time. - -## Dewey Integration - -When Dewey is running, Pinkman stores every evaluation as a semantic learning. This transforms `/scout` from a stateless tool into a knowledge-building system. - -### How Past Evaluations Inform Future Scouting - -1. **Automatic recall**: When you run `/scout` for a topic you have evaluated before, Pinkman queries Dewey for prior learnings. If you evaluated MCP servers last month, a new `/scout --trend MCP servers` command surfaces those earlier findings alongside fresh data. You see what changed without re-reading old reports. - -2. **Cross-project context**: Dewey indexes learnings across all your projects. If you evaluated `spf13/cobra` in Project A, that evaluation is available when you scout dependencies in Project B. Pinkman tells you: "Previously evaluated in project-a on 2026-08-01 — verdict: ADOPT (HIGH confidence)." - -3. **License pattern detection**: Over time, Pinkman builds a map of license changes across your dependency graph. If a maintainer has changed licenses on previous projects, Pinkman flags this pattern when you evaluate their new projects. This early warning helps you avoid dependencies with unstable licensing. - -4. **Contradiction resolution**: When a project's health metrics change between evaluations (e.g., maintenance score dropped from healthy to unmaintained), Dewey's compilation step resolves the contradiction temporally. The compiled article reflects the current state while preserving the history, so you can trace when and why a dependency's status changed. - -Start Dewey with `dewey serve` before your scouting session to enable this integration. Without Dewey, `/scout` still works — you just lose cross-session memory and must rely on the local report files in `.uf/pinkman/reports/`. diff --git a/openspec/changes/blog-tutorials-batch/tasks.md b/openspec/changes/blog-tutorials-batch/tasks.md index b4a7d66..4fb0380 100644 --- a/openspec/changes/blog-tutorials-batch/tasks.md +++ b/openspec/changes/blog-tutorials-batch/tasks.md @@ -36,7 +36,7 @@ All tutorials are independent files under the tutorials section created in group - [x] 3.1 [P] Create `content/docs/tutorials/dewey-knowledge-stores.md` — Setting up knowledge stores (issue #70, weight: 10) - [x] 3.2 [P] Create `content/docs/tutorials/dewey-provider-configuration.md` — Configuring embedding/synthesis providers (issue #114, weight: 20) - [x] 3.3 [P] Create `content/docs/tutorials/gaze-crap-baseline-ci.md` — CRAP baseline comparison in CI (issue #151, weight: 30) -- [x] 3.4 [P] Create `content/docs/tutorials/pinkman-oss-scout.md` — Getting started with /scout (issue #45, weight: 40) +- [x] ~~3.4 [P] Create `content/docs/tutorials/pinkman-oss-scout.md` — Getting started with /scout (issue #45, weight: 40)~~ **Removed per user direction** - [x] 3.5 [P] Create `content/docs/tutorials/onboard-customization.md` — Getting started with /onboard (issue #46, weight: 50) ## 4. Validation From a35df49b87e733efbef2019a5d379ab8d16baa2b Mon Sep 17 00:00:00 2001 From: Jay Flowers Date: Sun, 23 Aug 2026 20:11:07 -0400 Subject: [PATCH 4/7] chore: add code-review passed marker to tasks.md --- openspec/changes/blog-tutorials-batch/tasks.md | 1 + 1 file changed, 1 insertion(+) diff --git a/openspec/changes/blog-tutorials-batch/tasks.md b/openspec/changes/blog-tutorials-batch/tasks.md index 4fb0380..8bd184b 100644 --- a/openspec/changes/blog-tutorials-batch/tasks.md +++ b/openspec/changes/blog-tutorials-batch/tasks.md @@ -45,3 +45,4 @@ All tutorials are independent files under the tutorials section created in group - [x] 4.2 Verify tutorials section appears in sidebar at correct position (between Reference and Changelog) and blog posts appear in blog listing via `npm run dev` visual check + From 64b31fcc19a02dd7805045bc75ced8402c0171a7 Mon Sep 17 00:00:00 2001 From: Jay Flowers Date: Sun, 23 Aug 2026 20:30:03 -0400 Subject: [PATCH 5/7] chore: store retrospective learnings from blog-tutorials-batch Assisted-by: claude-opus Generated with AI assistance (claude-opus) --- ...blog-tutorials-batch-20260824T001123-jay-flowers.md | 10 ++++++++++ ...blog-tutorials-batch-20260824T001137-jay-flowers.md | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 .uf/dewey/learnings/blog-tutorials-batch-20260824T001123-jay-flowers.md create mode 100644 .uf/dewey/learnings/blog-tutorials-batch-20260824T001137-jay-flowers.md diff --git a/.uf/dewey/learnings/blog-tutorials-batch-20260824T001123-jay-flowers.md b/.uf/dewey/learnings/blog-tutorials-batch-20260824T001123-jay-flowers.md new file mode 100644 index 0000000..6537bbb --- /dev/null +++ b/.uf/dewey/learnings/blog-tutorials-batch-20260824T001123-jay-flowers.md @@ -0,0 +1,10 @@ +--- +tag: blog-tutorials-batch +author: jay-flowers +category: gotcha +created_at: 2026-08-24T00:11:23Z +identity: blog-tutorials-batch-20260824T001123-jay-flowers +tier: draft +--- + +When generating blog posts and tutorials in parallel batches for the Unbound Force website, cross-document consistency is the primary review failure mode. In the blog-tutorials-batch change, 5 out of 5 Divisor agents returned REQUEST CHANGES on the first code review iteration, with the most critical findings being inconsistencies between blog posts and their companion tutorials: different YAML schema formats (map-based vs list-based stores), different provider names (vertex-ai vs vertexai), different config paths (.dewey/ vs .uf/dewey/), different CLI flags (--json vs --format=json), and different model names (gemini-2.5-flash vs claude-sonnet-4-20250514). When parallel agents independently generate content from the same upstream issues, they produce internally consistent but mutually inconsistent documents. The fix is to either generate the tutorial first and pass it as context to the blog agent, or do a cross-document alignment pass before the code review step. Also, always verify cross-reference slugs against actual file slugs — the dewey-knowledge-stores blog referenced two non-existent blog post slugs that had to be corrected to the actual slugs (dewey-vs-karpathy, dewey-curator). diff --git a/.uf/dewey/learnings/blog-tutorials-batch-20260824T001137-jay-flowers.md b/.uf/dewey/learnings/blog-tutorials-batch-20260824T001137-jay-flowers.md new file mode 100644 index 0000000..0588da2 --- /dev/null +++ b/.uf/dewey/learnings/blog-tutorials-batch-20260824T001137-jay-flowers.md @@ -0,0 +1,10 @@ +--- +tag: blog-tutorials-batch +author: jay-flowers +category: pattern +created_at: 2026-08-24T00:11:37Z +identity: blog-tutorials-batch-20260824T001137-jay-flowers +tier: draft +--- + +For the Unbound Force website, FT-001 (code block language identifiers) is a consistent review finding when generating multiple content files. Blog posts and tutorials that contain output examples, interactive terminal sessions, or MCP tool calls frequently use bare opening fences without a language ID. The fix is straightforward — use `text` for output blocks and terminal sessions, `bash` for shell commands, and explicitly label MCP tool calls as `text` with a contextual note like "Run this MCP tool call in your AI agent session" since readers cannot paste MCP function calls into a terminal. Additionally, GitHub Actions workflow examples in blog posts must use SHA-pinned action references (not mutable tags like @v4) — this was caught in the gaze-baseline-comparison blog post where the companion tutorial correctly used SHA pins but the blog used @v4/@v5 tags. From 3dd0026808c3d52c0bb6bd6dd61e63fa3d379b10 Mon Sep 17 00:00:00 2001 From: Jay Flowers Date: Thu, 27 Aug 2026 15:20:25 -0400 Subject: [PATCH 6/7] fix(tutorials): add slug frontmatter and fix title with invalid / character Add slug: frontmatter to all 4 tutorials so Hugo generates URLs matching the filename stems used in internal links. Fix the onboard-customization title by removing the literal "/" that caused Hugo to produce a mangled URL path. Addresses PR #260 review feedback from @yvonnedevlinrh. Signed-off-by: jflowers Assisted-by: claude-opus --- content/docs/tutorials/dewey-knowledge-stores.md | 1 + content/docs/tutorials/dewey-provider-configuration.md | 1 + content/docs/tutorials/gaze-crap-baseline-ci.md | 1 + content/docs/tutorials/onboard-customization.md | 3 ++- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/content/docs/tutorials/dewey-knowledge-stores.md b/content/docs/tutorials/dewey-knowledge-stores.md index f0ebf7e..373b6a2 100644 --- a/content/docs/tutorials/dewey-knowledge-stores.md +++ b/content/docs/tutorials/dewey-knowledge-stores.md @@ -2,6 +2,7 @@ title: "Setting Up Dewey Knowledge Stores" description: "Step-by-step guide to configuring and using Dewey's curated knowledge stores — from configuration to semantic search with quality-scored, source-traced knowledge." lead: "Configure knowledge stores, run automated curation, and search structured knowledge extracted from your indexed sources." +slug: "dewey-knowledge-stores" date: 2026-08-23T00:00:00+00:00 draft: false weight: 10 diff --git a/content/docs/tutorials/dewey-provider-configuration.md b/content/docs/tutorials/dewey-provider-configuration.md index 00286da..84627de 100644 --- a/content/docs/tutorials/dewey-provider-configuration.md +++ b/content/docs/tutorials/dewey-provider-configuration.md @@ -2,6 +2,7 @@ title: "Configuring Dewey Embedding and Synthesis Providers" description: "Step-by-step guide for configuring Dewey's pluggable embedding and synthesis providers — covering both Ollama (default, local) and Vertex AI (cloud)." lead: "Switch between local Ollama and cloud Vertex AI for embeddings and synthesis. Mix providers for the best of both worlds." +slug: "dewey-provider-configuration" date: 2026-08-23T00:00:00+00:00 draft: false weight: 20 diff --git a/content/docs/tutorials/gaze-crap-baseline-ci.md b/content/docs/tutorials/gaze-crap-baseline-ci.md index f001cff..5da7298 100644 --- a/content/docs/tutorials/gaze-crap-baseline-ci.md +++ b/content/docs/tutorials/gaze-crap-baseline-ci.md @@ -2,6 +2,7 @@ title: "Setting Up CRAP Baseline Comparison in CI" description: "Step-by-step tutorial for setting up per-function CRAP regression detection using gaze's baseline comparison feature in GitHub Actions." lead: "Detect CRAP score regressions on every PR. Create a baseline, add a CI step, and gaze handles the rest — zero wrapper scripts required." +slug: "gaze-crap-baseline-ci" date: 2026-08-23T00:00:00+00:00 draft: false weight: 30 diff --git a/content/docs/tutorials/onboard-customization.md b/content/docs/tutorials/onboard-customization.md index 0748bc8..9a38dca 100644 --- a/content/docs/tutorials/onboard-customization.md +++ b/content/docs/tutorials/onboard-customization.md @@ -1,7 +1,8 @@ --- -title: "Getting Started with /onboard — Customizing Your Hero Experience" +title: "Getting Started with onboard — Customizing Your Hero Experience" description: "Step-by-step tutorial for using the /onboard command to capture your preferences and customize how Unbound Force heroes respond to your working style." lead: "Tell the heroes what matters to you. /onboard captures your inspiration, interests, and objectives into a profile that every hero reads — so they work the way you work." +slug: "onboard-customization" date: 2026-08-23T00:00:00+00:00 draft: false weight: 50 From 37e79bd0b5cd32bf162e1cca8fbac8094bce688a Mon Sep 17 00:00:00 2001 From: Jay Flowers Date: Thu, 27 Aug 2026 15:20:30 -0400 Subject: [PATCH 7/7] fix(spec): remove pinkman tutorial reference and correct counts Remove the Pinkman OSS Scout Tutorial requirement that was already struck from tasks.md. Update build validation scenario from "5 tutorials / 15 pages" to "4 tutorials / 14 pages" to match the actual implementation. Addresses PR #260 review feedback from @yvonnedevlinrh. Signed-off-by: jflowers Assisted-by: claude-opus --- .../changes/blog-tutorials-batch/specs/tutorials.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/openspec/changes/blog-tutorials-batch/specs/tutorials.md b/openspec/changes/blog-tutorials-batch/specs/tutorials.md index db92ed3..c2d83d8 100644 --- a/openspec/changes/blog-tutorials-batch/specs/tutorials.md +++ b/openspec/changes/blog-tutorials-batch/specs/tutorials.md @@ -59,15 +59,6 @@ The site MUST include a tutorial at `content/docs/tutorials/gaze-crap-baseline-c - **WHEN** a user navigates to `/docs/tutorials/gaze-crap-baseline-ci/` - **THEN** the page MUST render with GitHub Actions workflow examples and baseline comparison setup -### Requirement: Pinkman OSS Scout Tutorial (#45) - -The site MUST include a tutorial at `content/docs/tutorials/pinkman-oss-scout.md` covering the `/scout` command's four modes: discover, trend, audit, and report. - -#### Scenario: Tutorial renders at correct URL -- **GIVEN** the tutorial file exists in the tutorials directory -- **WHEN** a user navigates to `/docs/tutorials/pinkman-oss-scout/` -- **THEN** the page MUST render with usage examples for all four scout modes - ### Requirement: Onboard Customization Tutorial (#46) The site MUST include a tutorial at `content/docs/tutorials/onboard-customization.md` covering the `/onboard` command's three interview phases and hero experience customization. @@ -82,9 +73,9 @@ The site MUST include a tutorial at `content/docs/tutorials/onboard-customizatio After all content files are created, `npm run build` MUST succeed without errors. All new pages MUST appear in the site output. #### Scenario: Clean build with all new content -- **GIVEN** all 9 blog posts, 5 tutorials, and 1 section index have been created +- **GIVEN** all 9 blog posts, 4 tutorials, and 1 section index have been created - **WHEN** `npm run build` is executed -- **THEN** the build MUST complete successfully with exit code 0 and all 15 new pages MUST be present in the `public/` output directory +- **THEN** the build MUST complete successfully with exit code 0 and all 14 new pages MUST be present in the `public/` output directory ## MODIFIED Requirements