|
| 1 | +# Contributing to Nous |
| 2 | + |
| 3 | +Thanks for considering a contribution. Whether you're fixing a bug, adding a parser, writing an emitter, or improving documentation, this guide will get you oriented quickly. |
| 4 | + |
| 5 | +Nous is a monorepo managed with [pnpm workspaces](https://pnpm.io/workspaces) and [Turborepo](https://turbo.build/repo). Every package under `packages/` is independently buildable and publishable. Browse the [README](README.md) for a full package index and architecture overview. |
| 6 | + |
| 7 | +## Prerequisites |
| 8 | + |
| 9 | +- **Node.js** >= 20.0.0 |
| 10 | +- **pnpm** >= 10.18.0 (corepack-managed) |
| 11 | + |
| 12 | +```bash |
| 13 | +corepack enable |
| 14 | +corepack prepare pnpm@10.18.3 --activate |
| 15 | +``` |
| 16 | + |
| 17 | +## Setup |
| 18 | + |
| 19 | +```bash |
| 20 | +git clone https://github.com/salmad3/nousdev.git |
| 21 | +cd nousdev |
| 22 | +pnpm install |
| 23 | +pnpm build |
| 24 | +``` |
| 25 | + |
| 26 | +## Development Workflow |
| 27 | + |
| 28 | +### Building |
| 29 | + |
| 30 | +Turborepo handles dependency ordering across packages: |
| 31 | + |
| 32 | +```bash |
| 33 | +pnpm build # Build all packages |
| 34 | +pnpm dev # Start dev server with watch mode |
| 35 | +pnpm typecheck # Type-check all packages |
| 36 | +pnpm lint # Lint all packages |
| 37 | +pnpm test # Run all test suites |
| 38 | +``` |
| 39 | + |
| 40 | +To build a single package: |
| 41 | + |
| 42 | +```bash |
| 43 | +pnpm --filter @nousdev/agent-metadata build |
| 44 | +``` |
| 45 | + |
| 46 | +### Pre-Build Verification |
| 47 | + |
| 48 | +The `@nousdev/agent-metadata` package runs protocol version verification before every build via the `prebuild` npm lifecycle hook. This check scans emitter code, documentation, and type comments for version strings that have drifted from the centralized manifest at `packages/agent-metadata/src/protocols.ts`. |
| 49 | + |
| 50 | +If you update a protocol version, edit `protocols.ts` first, then run: |
| 51 | + |
| 52 | +```bash |
| 53 | +pnpm --filter @nousdev/agent-metadata verify-protocols |
| 54 | +``` |
| 55 | + |
| 56 | +The script identifies every stale reference with its file path and line number. |
| 57 | + |
| 58 | +### Running the Documentation Site |
| 59 | + |
| 60 | +```bash |
| 61 | +pnpm nous dev |
| 62 | +``` |
| 63 | + |
| 64 | +Opens at `http://localhost:4321`. The site is built entirely with Nous, with every page authored in KD. Changes to parsers, emitters, or the renderer are immediately visible here. |
| 65 | + |
| 66 | +## Architecture |
| 67 | + |
| 68 | +Nous processes documentation through a four-phase pipeline: |
| 69 | + |
| 70 | +1. **Parsing**: Format-specific parsers (`parser-kd`, `parser-md`, etc.) convert source files into the Nous Document Model (NDM), an immutable semantic AST. |
| 71 | + |
| 72 | +2. **Inference**: The inference engine analyzes parsed NDM nodes and attaches block-level annotations (`type`, `audience`, `answers`) to blocks that lack explicit metadata. |
| 73 | + |
| 74 | +3. **Transformation**: Plugins compose pure functions that receive document nodes and return new nodes without mutation. The `agent-metadata` plugin collects documents during this phase. |
| 75 | + |
| 76 | +4. **Emission**: The HTML renderer produces human-readable output. The agent-metadata plugin emits machine-readable formats (Schema.org JSON-LD, A2A agent cards, MCP resources, RAG chunks, llms.txt, AGENTS.md, and others). |
| 77 | + |
| 78 | +The NDM is the contract between parsers and consumers. Any format that can produce valid NDM nodes integrates with the full pipeline automatically. |
| 79 | + |
| 80 | +## Writing Parsers and Adapters |
| 81 | + |
| 82 | +Adding support for a new source format means writing an NDM adapter. KD and KDX have custom parsers because their block annotation model has no upstream equivalent. For other formats, adapters wrap an established parser and convert its AST into NDM nodes. |
| 83 | + |
| 84 | +Each parser package exports a single `parse` function: |
| 85 | + |
| 86 | +```typescript |
| 87 | +import type { DocumentNode } from '@nousdev/types'; |
| 88 | + |
| 89 | +export function parse(source: string, filePath: string): DocumentNode; |
| 90 | +``` |
| 91 | + |
| 92 | +The returned `DocumentNode` must conform to NDM types. Adapters should delegate syntax parsing to the upstream library and focus their logic on the AST-to-NDM conversion: mapping frontmatter, headings, code blocks, and (where available) semantic annotations into their corresponding NDM node types. |
| 93 | + |
| 94 | +## Writing Emitters |
| 95 | + |
| 96 | +Agent metadata emitters follow a consistent signature: |
| 97 | + |
| 98 | +```typescript |
| 99 | +import type { ExtractedMetadata, AgentMetadataConfig, EmitterOutput } from '@nousdev/agent-metadata'; |
| 100 | + |
| 101 | +export function emitMyFormat( |
| 102 | + metadata: ExtractedMetadata, |
| 103 | + config: AgentMetadataConfig, |
| 104 | +): MyFormatOutput; |
| 105 | +``` |
| 106 | + |
| 107 | +Register new emitters in `packages/agent-metadata/src/emitters/index.ts` by adding them to the `EMITTER_REGISTRY` and `ALL_EMITTERS` array. |
| 108 | + |
| 109 | +## Commit Conventions |
| 110 | + |
| 111 | +Follow [Conventional Commits](https://www.conventionalcommits.org/): |
| 112 | + |
| 113 | +``` |
| 114 | +<type>: <description> |
| 115 | +
|
| 116 | +<optional body> |
| 117 | +``` |
| 118 | + |
| 119 | +| Type | Usage | |
| 120 | +|------|-------| |
| 121 | +| `feat` | New feature or capability | |
| 122 | +| `fix` | Bug fix | |
| 123 | +| `refactor` | Code restructuring without behavior change | |
| 124 | +| `docs` | Documentation changes | |
| 125 | +| `test` | Adding or modifying tests | |
| 126 | +| `chore` | Build tooling, dependency updates, housekeeping | |
| 127 | +| `perf` | Performance improvement | |
| 128 | +| `ci` | CI/CD pipeline changes | |
| 129 | + |
| 130 | +Keep the subject line under 72 characters. Use the body for context on *why* the change was made when the diff alone does not make the rationale clear. |
| 131 | + |
| 132 | +## Pull Request Process |
| 133 | + |
| 134 | +1. Create a feature branch from `main`. |
| 135 | +2. Make changes, ensuring `pnpm build` and `pnpm test` pass. |
| 136 | +3. Write a PR description that includes: |
| 137 | + - A summary of what changed and why. |
| 138 | + - A test plan describing how to verify the changes. |
| 139 | +4. Request review. Address feedback as new commits rather than force-pushing, so reviewers can track incremental changes. |
| 140 | + |
| 141 | +## Code Standards |
| 142 | + |
| 143 | +These conventions keep the codebase consistent as it grows. They are enforced in review. |
| 144 | + |
| 145 | +- **Immutability**: Create new objects rather than mutating existing ones. Transforms return new document nodes; they never modify the input. |
| 146 | +- **Small files**: Aim for 200-400 lines per module. Extract utilities when files exceed 800 lines. |
| 147 | +- **Explicit error handling**: Handle errors at every level. Provide actionable messages. |
| 148 | +- **Input validation**: Validate at system boundaries (user config, file content, external protocol responses). |
| 149 | +- **No hardcoded protocol versions**: All version strings in `@nousdev/agent-metadata` must reference `protocols.ts` constants. The pre-build verification script enforces this. |
| 150 | + |
| 151 | +## Adding a New Package |
| 152 | + |
| 153 | +1. Create the directory under `packages/`. |
| 154 | +2. Add a `package.json` with the `@nousdev/` scope and appropriate `main`/`types` fields. |
| 155 | +3. Add a `tsconfig.json` extending the root config. |
| 156 | +4. Register the package in `pnpm-workspace.yaml` if not already covered by the glob pattern. |
| 157 | +5. Add build/test scripts and wire them into `turbo.json` if the package has build dependencies on other Nous packages. |
| 158 | + |
| 159 | +## Questions? |
| 160 | + |
| 161 | +Open an issue or start a discussion. We are happy to help you find the right entry point for your contribution. |
| 162 | + |
| 163 | +## License |
| 164 | + |
| 165 | +By contributing to Nous, you agree that your contributions will be licensed under the [MIT License](LICENSE). |
0 commit comments