Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Agent Notes

## Project Shape
- This is the npm package `@neuralnomads/nomadworks`, an OpenCode plugin. Source entrypoint is `src/index.js`; package entrypoint is built `dist/index.js`.
- The repo is ESM (`"type": "module"`). `typescript` is installed, but the build only copies JavaScript; there is no TS compile step.
- `npm pack` ships `dist`, `agents`, `docs`, `policies`, `templates`, and `Agents_Common.md`; update package contents with `package.json` `files` in mind.
- `.opencode/` has its own package lock for local OpenCode plugin state; the publishable package is the root npm package.

## Commands
- Install root dependencies with `npm ci`.
- Test all: `npm test`.
- Run one Jest file or focused test: `npm test -- tests/validate.test.js -t "Respects .gitignore"`.
- Build: `npm run build`. It deletes `dist/` and copies only `src/*.js` into `dist/`.
- Release check: `npm run release:check` runs `npm test`, then `npm run build`, then `npm pack --dry-run`.

## Plugin Runtime
- Runtime config is `.nomadworks/nomadworks.yaml`; some paths still fall back to legacy `.codenomad` locations.
- `nomadworks_init` requires `team_mode` of `mini` or `full` and only writes scaffold files when they do not already exist.
- `team_mode` defaults to `full`; `mini` enables only `product_manager`, `business_analyst`, and `tech_lead`. These three mandatory agents cannot be disabled.
- Repo-local full agent overrides live in `.nomadworks/agents/<agent>.md`; additive prompt fragments live in `.nomadworks/agent-additions/<agent>.md`; policy overrides live in `.nomadworks/policies/*.md`.
- Include resolution supports `<include:plugin:...>`, `<include:repo:...>`, and `<include:policy:...>`; policy includes prefer repo-local `.nomadworks/policies/` before bundled `policies/`.
- Unless `features.keep_builtin_agents: true`, config generation disables existing and built-in OpenCode agents (`build`, `plan`, `general`, `explore`) and sets `product_manager` as `default_agent`.
- Unless `features.debug_dumps: false`, resolved agent prompts are dumped to `.nomadworks/generated/agents/` during config resolution.
- `nomadflow_run_workflow` is only usable when `workflow_runner` is enabled and `team_mode` is `full`; it blocks a second active shared-worktree `implementation` workflow.

## Validation And CodeMaps
- `nomadworks_validate` fails immediately if root `codemap.yml` is missing.
- Validation honors `.gitignore`, skips hidden directory trees such as `.github/`, and exempts `tasks`, `evidences`, `docs`, `templates`, and `dist` from mandatory codemap and shadow-file checks.
- Module-scope codemaps must index every sibling source file with the extensions listed in `src/validate_logic.js`; unindexed source files fail validation.
- For `entrypoints`, `sources_of_truth`, and `links`, nested paths with `/` fail the Rule of Local Knowledge unless they start with `./`.
- Unresolved Markdown template placeholders fail validation outside `tasks/done`.

## Release
- CI release runs only on pushes to `dev` and `main` using Node.js 24, `npm ci`, then `npm run release:check`.
- `dev` publishes `<package.json version>-rc.N` with npm dist-tag `rc`; `N` is derived from already-published npm versions.
- `main` publishes the exact stable `package.json` version with dist-tag `latest` and fails if that version already exists.
- Keep `package.json` on a stable semver base; do not commit prerelease versions like `1.4.0-rc.2`.
- Publishing uses npm Trusted Publishing with provenance, not `NPM_TOKEN`.
24 changes: 24 additions & 0 deletions agents/codemap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
scope: module
parent: ../codemap.yml
name: agents
purpose: Bundled agent definitions shipped with the NomadWorks plugin.
entrypoints:
- path: product_manager.md
description: Product Manager Agent definition and orchestration prompt.
- path: workflow_runner.md
description: Workflow Runner agent definition for full-team delegated execution.
internals:
- path: business_analyst.md
description: Business Analyst agent definition.
- path: developer.md
description: Developer agent definition.
- path: qa_engineer.md
description: QA Engineer agent definition.
- path: tech_lead.md
description: Tech Lead agent definition.
- path: technical_architect.md
description: Technical Architect agent definition.
- path: ui_ux_designer.md
description: UI/UX Designer agent definition.
commands:
test: "npm test"
43 changes: 43 additions & 0 deletions codemap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
scope: repo
name: NomadWorks
purpose: >
Repository navigation index. Points to current-state
product specs, process docs, and module entrypoints.

code_roots:
- src/
- agents/
- policies/
- scripts/
- tests/

links:
- title: Global Context
path: Agents_Common.md
summary: "Core rules and agent roles."

- title: Orchestration Strategy
path: ./docs/core/agent_orchestration.md
summary: "Collaboration and handoff protocols."

- title: Technical Architecture
path: ./docs/architecture/TECHNICAL_ARCHITECTURE.md
summary: "Global patterns and tech stack."

entrypoints: []
commands:
test: "npm test"
build: "npm run build"
release_check: "npm run release:check"

modules:
- path: agents
summary: "Bundled NomadWorks agent prompt definitions."
- path: policies
summary: "Bundled repository policy documents included by agent prompts."
- path: scripts
summary: "Build and release utility scripts."
- path: src
summary: "OpenCode plugin source and validation logic."
- path: tests
summary: "Jest regression tests for plugin behavior and validation."
12 changes: 6 additions & 6 deletions docs/core/technical_guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
This document defines the project's tech stack and architectural patterns.

## Tech Stack
- **Language:** [To be defined]
- **Runtime/Framework:** [To be defined]
- **Frontend (if applicable):** [To be defined]
- **State Management:** [To be defined]
- **Testing Framework:** [To be defined]
- **Database/Storage:** [To be defined]
- **Language:** JavaScript (ES modules). TypeScript is available for tooling types, but package builds copy JavaScript sources without a TypeScript compile step.
- **Runtime/Framework:** Node.js package for the OpenCode plugin runtime.
- **Frontend (if applicable):** Not applicable; this repository does not ship a browser or native UI.
- **State Management:** YAML and JSON files for repository configuration, generated OpenCode configuration, task registries, SCR registries, and optional external workflow manifests.
- **Testing Framework:** Jest via `npm test`.
- **Database/Storage:** Filesystem-backed repository artifacts and optional external workflow storage; no application database is used.

## Architectural Patterns
- **Feature-First:** Organize code into distinct features or modules.
Expand Down
10 changes: 10 additions & 0 deletions docs/scrs/current.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Current Spec Change Requests (Backlog)

## Active/Review
- (None)

## Approved (Ready for Implementation)
- (None)

## Proposed
- (None)
4 changes: 4 additions & 0 deletions docs/scrs/done.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Implemented Spec Change Requests

| Date | SCR ID | Title | Related Feature | Task ID |
| :--- | :--- | :--- | :--- | :--- |
26 changes: 26 additions & 0 deletions policies/codemap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
scope: module
parent: ../codemap.yml
name: policies
purpose: Bundled policy documents that can be included by agent prompts or extracted for repository customization.
entrypoints:
- path: README.md
description: Policy include overview.
internals:
- path: definition-of-done.md
description: Definition of Done policy.
- path: definition-of-ready.md
description: Definition of Ready policy.
- path: development-guidelines.md
description: Development policy defaults.
- path: documentation-guidelines.md
description: Documentation policy defaults.
- path: git-commit-messaging.md
description: Commit message policy.
- path: product-guidelines.md
description: Product policy defaults.
- path: testing-guidelines.md
description: Testing policy defaults.
- path: ui-ux-guidelines.md
description: UI and UX policy defaults.
commands:
test: "npm test"
11 changes: 11 additions & 0 deletions scripts/codemap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
scope: module
parent: ../codemap.yml
name: scripts
purpose: Repository build and release helper scripts.
entrypoints:
- path: build.js
description: Copies source JavaScript files into dist for package builds.
- path: resolve-release-version.js
description: Resolves npm release versions for CI release workflows.
commands:
build: "npm run build"
13 changes: 13 additions & 0 deletions src/codemap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
scope: module
parent: ../codemap.yml
name: src
purpose: OpenCode plugin source for NomadWorks runtime tools and validation.
entrypoints:
- path: index.js
description: Plugin entrypoint exporting the NomadWorks OpenCode plugin and tool registrations.
internals:
- path: validate_logic.js
description: Shared CodeMap, placeholder, and repository validation implementation.
commands:
test: "npm test -- tests/validate.test.js"
build: "npm run build"
37 changes: 25 additions & 12 deletions src/validate_logic.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@ import path from "node:path";
import YAML from "yaml";
import ignore from "ignore";

export const toPosixRelativePath = (relPath) => relPath.replaceAll("\\", "/");

export const isIgnoredPath = (ig, relPath) => ig.ignores(toPosixRelativePath(relPath));

export const isOperationalPath = (relPath) => {
const normalizedRelPath = toPosixRelativePath(relPath);
const operationalFolders = ["tasks", "evidences", "docs", "templates", "dist"];
return operationalFolders.some(folder => normalizedRelPath === folder || normalizedRelPath.startsWith(`${folder}/`));
};

export const isPlaceholderExemptPath = (relPath) => {
const normalizedRelPath = toPosixRelativePath(relPath);
return normalizedRelPath === "tasks/done" || normalizedRelPath.startsWith("tasks/done/");
};

export const isHiddenTree = (relPath) => {
if (!relPath) return false;
return toPosixRelativePath(relPath).split("/").some(part => part.startsWith("."));
};

export async function nomadworks_validate_logic(worktree) {
const rootCodemapPath = path.join(worktree, "codemap.yml");
if (!fs.existsSync(rootCodemapPath)) {
Expand All @@ -25,16 +45,11 @@ export async function nomadworks_validate_logic(worktree) {
".php", ".rb", ".swift", ".kt", ".m", ".sh", ".sql", ".yaml", ".yml", ".json", ".md"
];

const isHiddenTree = (relPath) => {
if (!relPath) return false;
return relPath.split(path.sep).some(part => part.startsWith("."));
};

const isSourceDir = (dirPath) => {
const items = fs.readdirSync(dirPath, { withFileTypes: true });
for (const item of items) {
const relPath = path.relative(worktree, path.join(dirPath, item.name));
if (ig.ignores(relPath)) continue;
if (isIgnoredPath(ig, relPath)) continue;

if (item.isFile() && sourceExtensions.includes(path.extname(item.name))) return true;
if (item.isDirectory()) {
Expand Down Expand Up @@ -86,8 +101,7 @@ export async function nomadworks_validate_logic(worktree) {

// Shadow File Check: Ensure all source files in this directory are indexed (Module scope only)
const relDir = path.relative(worktree, dir);
const operationalFolders = ["tasks", "evidences", "docs", "templates", "dist"];
const isOperational = operationalFolders.some(f => relDir === f || relDir.startsWith(f + "/"));
const isOperational = isOperationalPath(relDir);

if (map.scope === "module" && !isOperational) {
const items = fs.readdirSync(dir, { withFileTypes: true });
Expand Down Expand Up @@ -119,14 +133,14 @@ export async function nomadworks_validate_logic(worktree) {

const walk = (dir) => {
const relDir = path.relative(worktree, dir);
if (relDir && ig.ignores(relDir)) return;
if (relDir && isIgnoredPath(ig, relDir)) return;
if (isHiddenTree(relDir)) return;

const hasCodemap = fs.existsSync(path.join(dir, "codemap.yml"));
const items = fs.readdirSync(dir, { withFileTypes: true });

// Check for placeholders in any .md file (except in tasks/done)
if (!relDir.startsWith("tasks/done")) {
if (!isPlaceholderExemptPath(relDir)) {
for (const item of items) {
if (item.isFile() && item.name.endsWith(".md")) {
const content = fs.readFileSync(path.join(dir, item.name), "utf8");
Expand All @@ -139,8 +153,7 @@ export async function nomadworks_validate_logic(worktree) {
}

// Exclusion list for mandatory codemaps (operational folders)
const operationalFolders = ["tasks", "evidences", "docs", "templates", "dist"];
const isOperational = operationalFolders.some(f => relDir === f || relDir.startsWith(f + "/"));
const isOperational = isOperationalPath(relDir);

if (relDir !== "" && !hasCodemap && isSourceDir(dir) && !isOperational) {
errors.push(`Missing CodeMap: Directory '${relDir}' contains source but has no codemap.yml.`);
Expand Down
13 changes: 13 additions & 0 deletions tasks/current.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Current Tasks (Backlog)

## Active Discussions
- (None)

## Active
- (None)

## Todo
- (None)

## Blocked
- (None)
5 changes: 5 additions & 0 deletions tasks/done.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Completed Tasks (Registry)

| Date | Task ID | SCR ID | Commit | Summary |
| :--- | :--- | :--- | :--- | :--- |
| 2026-05-15 | TASK-2026-05-15-001 | null | validation-hardening PR branch before merge | Hardened validation path handling, CodeMap template metadata, and onboarding artifact disposition. |
Loading