Skip to main content

add-route

Add (or rename, or change the shape of) an HTTP route in the nowledge axum service following the project's documented multi-file workflow. Use when the user says "add a route", "add an endpoint", "expose a new API", "wire up POST/GET/PUT/PATCH/DELETE /v1/...", or when changing an existing route's path/method/schema.

Jump to install

Source facts

Repository
dickwu/nowledge
Last source activity
July 7, 2026 at 03:43
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
add-route
description
Add (or rename, or change the shape of) an HTTP route in the nowledge axum service following the project's documented multi-file workflow. Use when the user says "add a route", "add an endpoint", "expose a new API", "wire up POST/GET/PUT/PATCH/DELETE /v1/...", or when changing an existing route's path/method/schema.
# add-route A new route in `nowledge` touches five files in a fixed order. Follow this checklist exactly — missing a step is the most common drift between the running service and the API docs. ## Inputs to gather first Before writing anything: 1. HTTP method (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`). 2. Path (e.g. `/v1/state/profile/facts/{fact_key}`). 3. Rust handler name (snake_case, matches `src/routes.rs::build_router` registration). 4. Group label for the manifest — pick from the existing `group` values in `doc/api_manifest.json` (e.g. `Health`, `Harness`, `Eval`, `Company Docs`); introduce a new group only for a genuinely new API surface. 5. Authentication mode: `None` | `UserGuard` | `UserGuard; owner default may apply` | `AdminGuard`. 6. Request and response schema names from `src/models.rs` (or new types you'll add there). ## Step 1 — code Edit in this order: 1. **`src/models.rs`** — add or update the request/response structs and any DTOs. Derive `Debug, Clone, Serialize, Deserialize` and skip empty `Option<...>` with `#[serde(skip_serializing_if = "Option::is_none")]`. If the route is owner-scoped, the request should carry an `Option<String> owner_user_id`. 2. **`src/store.rs`** — add the domain logic. Keep mutations behind `StoreData` and the `RwLock`. Use `util::new_id("prefix")` for new IDs and `EventIndexResolver::idempotency_hash` for any idempotency key. 3. **`src/repository.rs`** — only if the route needs to persist through the Meili backend. Add the trait method on `KnowledgeRepository`, implement on both `MeiliKnowledgeRepository` and `MemoryKnowledgeRepository`. Memory impl is usually a no-op. 4. **`src/routes.rs`** — register the handler in `build_router` and write the handler function. Use `State<AppState>`, the appropriate guard, and return `Result<Json<Response>, ApiError>`. For owner-scoped routes, call `guard.apply_owner_default(&mut req.owner_user_id)?` early. ## Step 2 — tests Add a regression test in `tests/api_spec.rs` (or a new dedicated test file if the surface is large). Use the existing helpers: - `app()` for unauthenticated runs. - `authed_app()` for owner-isolation tests (users `u1`, `u2`, `admin`). - `call(app, method, uri, body)` and `call_with_token(app, method, uri, body, Some(token))` for dispatch. At minimum cover the happy path. For owner-scoped routes, **always** add an owner-mismatch test (request from `u1` for `u2`'s data → 403). The owner-isolation invariant is load-bearing. ## Step 3 — docs (do not skip) Three coordinated updates: 1. **Create `doc/api/{method_lowercase}_{path_with_underscores}.md`** using the template from `doc/api/AGENTS.md`. Path braces are dropped; segments joined with `_`. Examples: - `GET /v1/fs/read` → `get_v1_fs_read.md` - `POST /v1/admin/history/user-event-indexes:reconcile` → `post_v1_admin_history_user_event_indexes_reconcile.md` Section order: Title (`# METHOD /path`), `## Summary`, `## Handler`, `## Path Parameters`, `## Query Parameters`, `## JSON Body Parameters` (with `Schema:` line referencing the type in `src/models.rs`), `## Response`, `## Errors and Access Rules`, `## Internal Logic Call Graph` (a Mermaid `flowchart TD`). 2. **Add a row to the index table in `doc/README.md`**, alphabetized within its method group: ```markdown | `METHOD` | `/v1/path` | `handler_name` | [api/<file>.md](api/<file>.md) | ``` 3. **Append an entry to `doc/api_manifest.json`**: ```json { "method": "METHOD", "path": "/v1/path", "handler": "handler_name", "group": "GroupLabel", "file": "api/<file>.md" } ``` ## Step 4 — verify Run the `/verify` gauntlet. If you bumped a public response shape, also rerun the relevant integration block by hand to confirm the docs match runtime behavior. ## Cross-check After everything is in place: ```sh grep -nE '\.route\("' src/routes.rs | wc -l ls doc/api/ | wc -l jq 'length' doc/api_manifest.json ``` The doc count and manifest count must match the number of registered routes. When the count changes, update the "Total documented APIs" line in `doc/README.md` to match.
View on GitHub