Restructure agent setup

This commit is contained in:
2026-07-05 19:00:24 +01:00
parent 1e0c195f42
commit 79c5d368bf
5 changed files with 230 additions and 61 deletions
+56
View File
@@ -0,0 +1,56 @@
---
name: prism-dag
description: DAG / graph patterns for Prism — adjacency list rules, arena allocation, Kahn's algorithm, flat buffer layout
license: MIT
compatibility: opencode
metadata:
domain: core
---
## What I do
Captures the conventions for Prism's directed acyclic graph (DAG) implementation: how edges are stored, how the graph is validated, and how to avoid common pitfalls.
## When to use me
Use this when working on graph/DAG structures (`pr_graph.h`, `pr_graph.c`, or `scratchpad/dag.c`), adding new node types, or modifying the topological sort / cycle detection logic.
## Conventions
### Adjacency lists — separate edge nodes
Adjacency list nodes must be **separately allocated from the vertex array**. Never use the vertex struct itself as a linked-list node in another vertex's adjacency chain — that shares the `next` pointer between two roles and corrupts the graph.
```c
// correct — per-edge copy on the arena
static void addEdge(PrGraph *g, const WpAllocator *alloc, u64 from, u64 to) {
PrVertex *src = &g->vertices[from];
PrVertex *dst = wpMemAllocatorAlloc(alloc, sizeof(PrVertex));
if (!dst) { /* handle OOM */ return; }
dst->id = g->vertices[to].id;
dst->value = g->vertices[to].value;
dst->next = src->next;
src->next = dst;
}
// wrong — reuses the destination vertex as the list node
static void addEdge_bad(PrGraph *g, u64 from, u64 to) {
PrVertex *src = &g->vertices[from];
PrVertex *dest = &g->vertices[to];
dest->next = src->next;
src->next = dest; // overwrites dest->next used elsewhere
}
```
Arena bump allocation (`wpMemAllocatorAlloc`) is the natural fit for edge nodes. Always NULL-check the result — arena allocators can fail if the backing buffer is exhausted.
### Flat buffer layout
For hot-path graph evaluation, prefer SoA layouts and keep the DAG in contiguous arrays rather than individually allocated linked structures.
### Cycle detection
Use Kahn's algorithm integrated into `prGraphAddEdge` for cycle detection with rollback. When an edge would create a cycle, the edge is not added and the function returns an error.
### Memory management
Stack-allocate where possible; pass `WpAllocator *` explicitly for heap allocations.
+74
View File
@@ -0,0 +1,74 @@
---
name: prism-rhi
description: RHI (Rendering Hardware Interface) patterns — compile-time dispatch, by-value desc structs, wapp array aliases, backend file layout
license: MIT
compatibility: opencode
metadata:
domain: rendering
---
## What I do
Captures the RHI conventions for Prism: how backends are dispatched, how descriptor structs and arrays are handled, and how the files are organized.
## When to use me
Use this when working on any file in `scratchpad/rhi/` or `src/prism/rhi/`, or when creating a new backend (Vulkan, D3D12, Metal).
## Conventions
### Backend dispatch
Backend selection is compile-time via `-D PR_RHI_VULKAN` / `-D PR_RHI_D3D12` / `-D PR_RHI_METAL`. The umbrella header `pr_rhi.h` includes the appropriate alias file:
```c
#if defined(PR_RHI_VULKAN)
# include "vulkan/pr_rhi_vk_aliases.h"
#elif defined(PR_RHI_D3D12)
# include "d3d12/pr_rhi_d3d12_aliases.h"
#elif defined(PR_RHI_METAL)
# include "metal/pr_rhi_metal_aliases.h"
#else
# error "Define one of: PR_RHI_VULKAN, PR_RHI_D3D12, PR_RHI_METAL"
#endif
```
Each `_aliases.h` file maps generic names to backend-specific names:
```c
#define prRhiCreateDevice prRhiCreateDeviceVk
#define prRhiCreateSwapchain prRhiCreateSwapchainVk
#define prRhiCreateBuffer prRhiCreateBufferVk
// …
```
Backend implementations are suffixed with the backend name: `pr_rhi_vk_device.c`, `pr_rhi_vk_swapchain.c`, etc.
### Desc structs
All descriptor structs are passed **by value**, not `const *`:
```c
// correct
PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface,
PrRhiDeviceDesc desc, WpAllocator *alloc);
// wrong
PrRhiDevice *prRhiCreateDevice(PrRhiPhysicalDevice *pdev, PrRhiSurface *surface,
const PrRhiDeviceDesc *desc, WpAllocator *alloc);
```
### File layout
```
scratchpad/rhi/
├── pr_rhi.h ← umbrella header (API declarations + backend dispatch)
├── pr_rhi_types.h ← shared types (enums, element types, array aliases, desc structs, opaque handles)
├── vulkan/
│ ├── pr_rhi_vk.h ← Vulkan backend header (opaque struct defs + Vk-suffixed decls)
│ └── pr_rhi_vk_aliases.h ← #define alias mapping
├── d3d12/
│ └── …
└── metal/
└── …
```
+42 -61
View File
@@ -9,7 +9,7 @@ are rendered via GPU shaders.
- **Language**: C11 / C++11 (dual-mode, like `src/wapp/`) - **Language**: C11 / C++11 (dual-mode, like `src/wapp/`)
- **GPU API**: Vulkan, abstracted behind a Rendering Hardware Interface (RHI) - **GPU API**: Vulkan, abstracted behind a Rendering Hardware Interface (RHI)
- **Shading language**: Slang, stored in external `.slang` files under `src/shaders/` - **Shading language**: Slang, stored in external `.slang` files under `src/shaders/`
- **Build**: TBD — either a standalone shell build script or a `justfile` (Just) - **Build**: `justfile` (Just) as a task runner
- **Dependencies**: `src/wapp/` (local utility library, already vendored) - **Dependencies**: `src/wapp/` (local utility library, already vendored)
## Coding Conventions ## Coding Conventions
@@ -34,25 +34,20 @@ All code follows the patterns established in `src/wapp/`. The project prefix is
### Formatting ### Formatting
- **Indentation**: tabs (no spaces). Tab width is a viewer preference. Machine-enforceable rules (tabs, braces, pointer alignment, continuation
- **Braces**: always required after `if`, `else`, `for`, `while`, `do` — even alignment) are in `.clang-format` — run `clang-format -i <file>` to apply.
when the body is a single statement. This avoids ambiguity and makes diffs
cleaner.
```c - **Return-type alignment**: Within each `// =====` section, align function
// correct declaration names so the first letter of every function occupies the same
if (condition) { column. For pointer return types, place `*` directly against the function
do_thing(); name (no space) and put all alignment padding between the type name and `*`.
} ```c
// correct — * against fn name, padding before *
for (int i = 0; i < n; i++) { PrRhiSwapchain *prRhiCreateSwapchain(…);
process(i); void prRhiDestroySwapchain(…);
} PrRhiSwapchainResult prRhiAcquireNextImage(…);
```
// wrong — no braces, spaces instead of tabs This cannot be automated by clang-format and must be done manually.
if (condition)
do_thing();
```
### Storage qualifiers ### Storage qualifiers
@@ -171,6 +166,16 @@ Always use typed array aliases (`WpU64Array`, `PrNodeIdArray`, etc.) rather
than raw pointers when declaring array variables. Follow the existing typedef than raw pointers when declaring array variables. Follow the existing typedef
pattern in the module (`typedef Type *TypeArray`). pattern in the module (`typedef Type *TypeArray`).
Typedef pattern:
- Opaque handles use `**` (pointer-to-pointer)
- Value types use `*` (contiguous block)
```c
typedef PrRhiBuffer **PrRhiBufferArray; // opaque handles → **
typedef PrRhiColorAttachment *PrRhiColorAttachmentArray; // value types → *
```
Group opaque handle arrays first, value type arrays second, separated by a
blank line.
Use named init flags (`WP_ARRAY_INIT_NONE`, `WP_ARRAY_INIT_FILLED`) instead of Use named init flags (`WP_ARRAY_INIT_NONE`, `WP_ARRAY_INIT_FILLED`) instead of
bare `0` — they make the initialisation policy explicit. bare `0` — they make the initialisation policy explicit.
@@ -202,10 +207,21 @@ documents/
├── RENDERING_HARDWARE_INTERFACE.md ├── RENDERING_HARDWARE_INTERFACE.md
├── NODE_SYSTEM.md ├── NODE_SYSTEM.md
├── ROADMAP.md ├── ROADMAP.md
── research/ ── research/
└── vulkan-baseline.md └── <topic>.md
└── session-logs/
└── YYYY-MM-DD.md
``` ```
## Skills
Domain-specific conventions are stored as skills in `.opencode/skills/<name>/SKILL.md`.
These are loaded on-demand by the AI agent when a task matches their description,
keeping AGENTS.md lean.
- **`prism-rhi`** — RHI backend dispatch, by-value descs, file layout
- **`prism-dag`** — DAG adjacency lists, arena allocation, Kahn's algorithm
## Workflows for AI agents ## Workflows for AI agents
### Research / planning ### Research / planning
@@ -215,20 +231,12 @@ documents/
a summary; iterate on the plan before writing any code. a summary; iterate on the plan before writing any code.
3. Only start implementing after the plan is approved. 3. Only start implementing after the plan is approved.
### README ### Skill maintenance
Keep `README.md` in sync with the project as it evolves. Update it when: When you observe the user correcting your output (e.g. formatting, conventions),
- The directory layout changes meaningfully infer the rule and add it to the relevant skill's `SKILL.md`. If no skill
- Language, toolchain, or build system decisions are settled matches, add a new one. This keeps AGENTS.md focused on project identity and
- Dependencies are added or removed critical workflow rules rather than accumulating domain details.
- The project reaches a notable milestone
### Learning from edits
The user may edit code produced by AI agents. When this happens, infer the
reason for the change and update AGENTS.md with any new conventions, patterns,
or constraints that the edit reveals. This keeps the guide aligned with the
user's evolving preferences.
### Committing ### Committing
@@ -236,30 +244,3 @@ Only commit when explicitly asked. When asked:
- Stage only intended files. - Stage only intended files.
- Write a short, conventional commit message in present tense. - Write a short, conventional commit message in present tense.
- Never amend, force-push, or create PRs without a request. - Never amend, force-push, or create PRs without a request.
## Session Log — 2026-07-05
### Completed
- **DAG refactoring** (`scratchpad/dag.c`): Decoupled PrGraph from PrNodeManager.
Graph tracks its own active vertices (`vertex_count`, `max_vertex_ever`, `b8 active`).
`prGraphAddEdge`, `prGraphTopologicalSort` no longer take `PrNodeManager*`.
Kahn's algorithm integrated into `prGraphAddEdge` for cycle detection with rollback.
Output verified matching baseline.
- **RHI research document** written to `documents/research/rendering-hardware-interface.md`.
Covers 8 reference RHIs, architecture patterns, core API surface, Vulkan-specific
considerations, Slang integration, and proposed directory layout / lifecycle design.
- Added NVRHI to `documents/resources.md`.
### Key Decisions
- Graph API is self-contained — no graphics or node-manager dependencies.
- RHI will use object-based + command-list-oriented architecture with vtbl dispatch.
- Object lifecycle: `prRhiCreate*` / `prRhiDestroy*` with explicit `WpAllocator*`.
- All GPU state explicit (no hidden pipeline state).
- Per-frame command pools and descriptor pools, arena-allocated scratch.
- `#version-macro` convention removed from Slang files; `__slang` define used instead.
### Next Steps
1. User reviews RHI research document, then iterate if needed.
2. Begin implementing RHI layer: types header, device creation, Vulkan backend skeleton.
3. Implement Slang shader compilation + reflection integration.
4. Wire up per-frame lifecycle (command pool reset, descriptor pool reset, scratch reset).
+36
View File
@@ -0,0 +1,36 @@
# Session Log — 2026-07-05
## Completed
- **DAG refactoring** (`scratchpad/dag.c`): Decoupled PrGraph from PrNodeManager.
Graph tracks its own active vertices (`vertex_count`, `max_vertex_ever`, `b8 active`).
`prGraphAddEdge`, `prGraphTopologicalSort` no longer take `PrNodeManager*`.
Kahn's algorithm integrated into `prGraphAddEdge` for cycle detection with rollback.
Output verified matching baseline.
- **RHI research document** written to `documents/research/rendering-hardware-interface.md`.
Covers 8 reference RHIs, architecture patterns, core API surface, Vulkan-specific
considerations, Slang integration, and proposed directory layout / lifecycle design.
- Added NVRHI to `documents/resources.md`.
- **RHI API surface** (`scratchpad/rhi/pr_rhi.h`, `pr_rhi_types.h`): Full RHI API
designed with compile-time alias dispatch, by-value desc structs, wapp array types
for pointer+count replacement, `PrRhiSwapchainResult` enum, surface capabilities,
compute pipeline support, all primitive topologies, and aligned function declarations
grouped by subsystem section.
- **Initial opencode setup** (opencode.json, justfile, skills, trimmed AGENTS.md).
## Key Decisions
- Graph API is self-contained — no graphics or node-manager dependencies.
- RHI will use compile-time alias dispatch (`#define prRhiCreateDevice prRhiCreateDeviceVk`)
over vtbl — zero runtime overhead, dead-stripping, separate builds per backend.
- `justfile` (Just) as task runner.
- Object lifecycle: `prRhiCreate*` / `prRhiDestroy*` with explicit `WpAllocator*`.
- All GPU state explicit (no hidden pipeline state).
- Per-frame command pools and descriptor pools, arena-allocated scratch.
- `#version-macro` convention removed from Slang files; `__slang` define used instead.
- Desc structs passed by value (not `const *`) for simpler caller ergonomics.
- Array aliases grouped: opaque handles (`**`) first, value types (`*`) second, separated
by blank line — element types before array aliases before desc structs.
## Next Steps
- Begin Vulkan backend implementation starting with `pr_rhi_vk_device.c` (instance/device/surface/swapchain creation).
- Implement Slang shader compilation + reflection integration.
- Wire up per-frame lifecycle (command pool reset, descriptor pool reset, scratch reset).
+22
View File
@@ -0,0 +1,22 @@
{
"$schema": "https://opencode.ai/config.json",
"command": {
"build": {
"template": "!just build",
"description": "Build the project"
},
"lint": {
"template": "!just lint",
"description": "Run linter / typecheck"
},
"test": {
"template": "!just test",
"description": "Run tests"
}
},
"permission": {
"edit": {
"src/wapp/**": "deny"
}
}
}