- Deno 2.x
deno task check # type checking
deno task test # test suite
deno lint # lintingdeno task compileThis produces a porter executable in the project root.
- Fork the repository
- Create a feature branch from
main - Make your changes
- Run
deno task checkanddeno task testto verify - Open a pull request against
main
Patterns are JSON-LD definitions -- adding one requires no code changes.
- Create a
.jsonldfile following thePatternDefinitionschema (seedocs/collaboration-patterns.mdfor the full format). Include the inline@context, set@typeto"Pattern", and give it a unique@idof the formporter:pattern/<id>. - Place the file in
src/orchestration/patterns/. - Add the filename to the
builtinsarray insrc/orchestration/pattern_registry.ts(the registry prefers.jsonldover.json). - Add an example config in
examples/. - Add tests in
test/patterns_test.ts(see "Test Structure" below).
Custom patterns can be created entirely at runtime:
- Via the UI: Open the Patterns panel, click "New Pattern", use the visual editor to define roles and connections, then save. The editor generates the
bus_flowstring from your topology automatically. - Via upload: Write a
.jsonldfile and upload it through the Patterns panel. - Via API:
POST /api/patternswith the pattern definition as the request body.
See docs/collaboration-patterns.md for the full pattern definition format, bus_flow syntax, and SHACL validation rules.
Pattern-specific tools are auto-injected at runtime via a role's auto_tools array. To add a new coordination tool:
- Implement the tool handler (input validation, graph read/write).
- Register it in the runtime tool registry.
- Reference the tool name in the pattern definition's
auto_toolsarray for the appropriate role. - If the tool should participate in the inference engine's intent classification, add regex patterns to the
INTENT_SIGNALSarray insrc/tools/inference_engine.tsand follow-up chains toFOLLOW_UP_MAP.
Existing auto-injected tools and their roles:
| Tool | Used By | Purpose |
|---|---|---|
finding_write |
Mixture Specialist | Record findings to graph |
findings_query |
Mixture Synthesizer | Query all findings from graph |
critique_write |
Deliberation Reflector | Write critique to graph |
critiques_query |
Deliberation Worker | Read critiques from graph |
approve |
Deliberation Reflector | End deliberation loop |
plan_write |
Distillation Expert | Write plan steps to graph |
plan_query |
Distillation Learner | Read next pending step |
step_update |
Distillation Learner | Mark step done/failed |
Porter represents agents, teams, and patterns as RDF resources using the porter: vocabulary (https://porter.chapeaux.io/vocab#).
Two JSON-LD contexts define the vocabulary mappings:
src/orchestration/patterns/context.jsonld-- Pattern vocabulary:Pattern,PatternRole,busFlow,hasRole,minCount,maxCount,autoTool,subscribesTo, etc.src/agents/context.jsonld-- Agent vocabulary:Agent,name,agentExpertise,usesModel,hasTool,reasoning,maxTokens,visibility,derivedFrom,linkedFrom.
Agents and teams are serialized as Turtle for Solid Pod storage (src/ui/sync/sync-helpers.js):
agentToTurtle(agent, uri)-- Producesporter:Agentwithporter:name,porter:assignedRole,porter:agentExpertise,porter:hasTool,porter:subscribesTo,porter:usesModel, etc.teamToTurtle(team, uri)-- Producesporter:Teamwithporter:name,porter:teamPattern,porter:hasAgentRef(blank nodes), andporter:configJsonfor lossless round-tripping.
src/orchestration/patterns/pattern-shapes.ttl defines SHACL shapes for porter:Pattern and porter:PatternRole, enforcing required properties and cardinality on save.
src/orchestration/pattern_registry.ts provides patternToJsonLd() and jsonLdToPattern() for converting between the internal PatternDefinition type and JSON-LD documents. The parser handles both inline-context short names (roles, min, max) and external-context full names (hasRole, minCount, maxCount).
The test suite currently has 312 tests across 23 test files in test/.
deno task test # all tests
deno test test/patterns_test.ts # pattern tests onlyPattern-specific tests are in test/patterns_test.ts. When adding a pattern, test:
- Registration and retrieval via
getPattern()andlistPatterns() - Team composition validation via
validateTeamComposition()(both valid and invalid cases) - Min/max enforcement for each role
- JSON-LD round-tripping via
patternToJsonLd()andjsonLdToPattern() - Composition summary via
getCompositionSummary()
- Test files are named
*_test.tsin thetest/directory - Use
Deno.test()with descriptive names - Import
resetPatternRegistry()for test isolation when testing pattern registry state - Tests run in parallel by default
- Follow existing patterns in the codebase
- No comments unless they explain why, not what