feat: add developer skill — coding conventions + architecture guide
Adds 'uwf skill developer' for contributors to the workflow engine. Covers: monorepo structure, dependency layers, functional-first conventions, error handling, logging with tagged logger, development workflow, testing, publishing, key modules (moderator, extract pipeline, createAgent). Refs #541
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
cmdSkillArchitecture,
|
||||
cmdSkillAuthor,
|
||||
cmdSkillCli,
|
||||
cmdSkillDeveloper,
|
||||
cmdSkillList,
|
||||
cmdSkillModerator,
|
||||
cmdSkillUser,
|
||||
@@ -27,6 +28,7 @@ describe("skill commands", () => {
|
||||
expect(result).toContain("actor");
|
||||
expect(result).toContain("user");
|
||||
expect(result).toContain("author");
|
||||
expect(result).toContain("developer");
|
||||
for (const name of result) {
|
||||
expect(name).toMatch(/^\S+$/);
|
||||
}
|
||||
@@ -97,6 +99,15 @@ describe("skill commands", () => {
|
||||
expect(result.length).toBeGreaterThan(500);
|
||||
});
|
||||
|
||||
test("skill developer returns non-empty markdown string", () => {
|
||||
const result = cmdSkillDeveloper();
|
||||
expect(typeof result).toBe("string");
|
||||
expect(result).toContain("Monorepo");
|
||||
expect(result).toContain("CAS");
|
||||
expect(result).toContain("Biome");
|
||||
expect(result.length).toBeGreaterThan(500);
|
||||
});
|
||||
|
||||
test("skill help subcommand is suppressed", () => {
|
||||
const output = execFileSync("bun", ["src/cli.ts", "skill", "--help"], {
|
||||
cwd: join(__dirname, "..", ".."),
|
||||
@@ -111,6 +122,7 @@ describe("skill commands", () => {
|
||||
expect(output).toContain("actor");
|
||||
expect(output).toContain("user");
|
||||
expect(output).toContain("author");
|
||||
expect(output).toContain("developer");
|
||||
expect(output).toContain("list");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
cmdSkillArchitecture,
|
||||
cmdSkillAuthor,
|
||||
cmdSkillCli,
|
||||
cmdSkillDeveloper,
|
||||
cmdSkillList,
|
||||
cmdSkillModerator,
|
||||
cmdSkillUser,
|
||||
@@ -520,6 +521,13 @@ skill
|
||||
console.log(cmdSkillAuthor());
|
||||
});
|
||||
|
||||
skill
|
||||
.command("developer")
|
||||
.description("Print the developer reference (coding conventions + architecture)")
|
||||
.action(() => {
|
||||
console.log(cmdSkillDeveloper());
|
||||
});
|
||||
|
||||
skill
|
||||
.command("moderator")
|
||||
.description("Print the moderator reference")
|
||||
|
||||
@@ -3,6 +3,7 @@ export {
|
||||
generateArchitectureReference as cmdSkillArchitecture,
|
||||
generateAuthorReference as cmdSkillAuthor,
|
||||
generateCliReference as cmdSkillCli,
|
||||
generateDeveloperReference as cmdSkillDeveloper,
|
||||
generateModeratorReference as cmdSkillModerator,
|
||||
generateUserReference as cmdSkillUser,
|
||||
generateYamlReference as cmdSkillYaml,
|
||||
@@ -16,6 +17,7 @@ const SKILL_NAMES = [
|
||||
"actor",
|
||||
"user",
|
||||
"author",
|
||||
"developer",
|
||||
] as const;
|
||||
|
||||
export function cmdSkillList(): ReadonlyArray<string> {
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
export function generateDeveloperReference(): string {
|
||||
return `# Developer Reference
|
||||
|
||||
Guide for contributing to the workflow engine codebase.
|
||||
|
||||
## Monorepo Structure
|
||||
|
||||
\`\`\`
|
||||
packages/
|
||||
workflow-protocol/ # Shared types (WorkflowPayload, StepNodePayload, etc.)
|
||||
workflow-util/ # Base32, ULID, logger, frontmatter parsing, skill references
|
||||
workflow-util-agent/ # createAgent factory, context builder, extract pipeline
|
||||
workflow-agent-hermes/ # uwf-hermes CLI (spawns Hermes chat sessions)
|
||||
workflow-agent-builtin/ # uwf-builtin CLI (direct LLM calls via OpenAI API)
|
||||
cli-workflow/ # uwf CLI (moderator, thread/step/cas/config commands)
|
||||
\`\`\`
|
||||
|
||||
Dependency layers (each only imports from packages above it):
|
||||
\`\`\`
|
||||
protocol → util → util-agent → agent-hermes / agent-builtin / cli-workflow
|
||||
\`\`\`
|
||||
|
||||
External CAS: \`@uncaged/json-cas\` (store API, hashing, schema validation) + \`@uncaged/json-cas-fs\` (filesystem backend).
|
||||
|
||||
## Coding Conventions
|
||||
|
||||
### Functional-first
|
||||
|
||||
| Rule | Description |
|
||||
|------|-------------|
|
||||
| \`type\` over \`interface\` | All type definitions use \`type\` |
|
||||
| \`function\` over \`class\` | Pure functions + closures, no class |
|
||||
| No \`this\` | Functions must not depend on \`this\` context |
|
||||
| No inheritance | No \`extends\`, \`implements\`, \`abstract\` |
|
||||
| No optional properties | Use \`T \\| null\` instead of \`?:\` |
|
||||
| Immutability first | Use \`Readonly<T>\`, \`as const\`, avoid mutation |
|
||||
|
||||
Classes allowed only when required by third-party libraries or for Error subclasses.
|
||||
|
||||
### Error Handling
|
||||
|
||||
- \`Result<T, E>\` type for expected failures (\`ok\`/\`err\` constructors from \`@uncaged/workflow-util\`)
|
||||
- \`throw\` only for unrecoverable bugs
|
||||
- No try-catch for flow control
|
||||
|
||||
### Async
|
||||
|
||||
Always \`async/await\`, never \`.then()\` chains.
|
||||
|
||||
### Logging
|
||||
|
||||
\`console.*\` is banned (Biome \`noConsole\` rule). Use the structured logger:
|
||||
|
||||
\`\`\`typescript
|
||||
import { createLogger } from "@uncaged/workflow-util";
|
||||
const log = createLogger();
|
||||
log("4KNMR2PX", "Loading workflow..."); // 8-char Crockford Base32 tag
|
||||
\`\`\`
|
||||
|
||||
Each call site gets a unique hand-written tag. \`grep "4KNMR2PX"\` in logs → instant code location.
|
||||
|
||||
CLI package (\`@uncaged/cli-workflow\`) may use \`console.log\` for user-facing output with a biome-ignore comment.
|
||||
|
||||
### No Dynamic Import
|
||||
|
||||
No \`await import()\` in production code. Always static top-level \`import\`. Test files are exempt.
|
||||
|
||||
### Naming
|
||||
|
||||
- Workflow names: verb-first kebab-case (\`solve-issue\`, \`review-code\`)
|
||||
- IDs: Crockford Base32 — CAS hash (XXH64, 13-char), Thread ID (ULID, 26-char)
|
||||
|
||||
## Development Workflow
|
||||
|
||||
\`\`\`bash
|
||||
bun install # install all workspace deps
|
||||
bun run build # tsc --build (all packages)
|
||||
bun run check # tsc + biome check + lint-log-tags
|
||||
bun run format # biome format --write
|
||||
bun test # run all tests
|
||||
\`\`\`
|
||||
|
||||
Before committing: \`bun run check\` + \`bun test\` must both pass.
|
||||
|
||||
### Testing
|
||||
|
||||
- \`cli-workflow\`: vitest
|
||||
- Other packages: \`bun test\`
|
||||
- Test files live in \`__tests__/\` directories
|
||||
|
||||
### Publishing
|
||||
|
||||
Fixed-mode versioning — all \`@uncaged/*\` packages share the same version number.
|
||||
|
||||
\`\`\`bash
|
||||
bun changeset # describe the change
|
||||
bun version # bump versions + changelogs
|
||||
bun release # build + test + publish to npmjs
|
||||
\`\`\`
|
||||
|
||||
## Key Modules
|
||||
|
||||
### Moderator (\`cli-workflow/src/moderator/\`)
|
||||
|
||||
Status-based graph evaluator. Reads \`graph[lastRole][output.$status]\` to determine the next role. Zero LLM cost.
|
||||
|
||||
### Extract Pipeline (\`workflow-util-agent/src/\`)
|
||||
|
||||
1. Agent produces frontmatter markdown
|
||||
2. \`parseFrontmatterMarkdown()\` extracts YAML frontmatter
|
||||
3. \`tryFrontmatterFastPath()\` validates against role's output schema
|
||||
4. If fast path fails, retries up to 2 times via agent continue
|
||||
5. Validated output stored as CAS node
|
||||
|
||||
### createAgent Factory (\`workflow-util-agent/src/run.ts\`)
|
||||
|
||||
Shared entry point for all agent CLIs. Handles:
|
||||
- Argument parsing (\`--thread\`, \`--role\`, \`--prompt\`)
|
||||
- Context building (thread history, workflow definition)
|
||||
- Output extraction and CAS persistence
|
||||
- Frontmatter retry loop
|
||||
|
||||
### CAS Integration
|
||||
|
||||
All data is CAS-addressed via \`@uncaged/json-cas\`:
|
||||
- \`store.put(schemaHash, data)\` → content hash
|
||||
- \`store.get(hash)\` → node
|
||||
- \`validate(store, node)\` → schema check
|
||||
- Schemas registered at workflow add time
|
||||
|
||||
## Commit Convention
|
||||
|
||||
\`\`\`
|
||||
<type>(<scope>): <description>
|
||||
|
||||
type: feat | fix | refactor | docs | chore | test
|
||||
scope: workflow | cli | moderator | agent-kit | hermes | util | protocol
|
||||
\`\`\`
|
||||
`;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ export { generateArchitectureReference } from "./architecture-reference.js";
|
||||
export { generateAuthorReference } from "./author-reference.js";
|
||||
export { encodeUint64AsCrockford } from "./base32.js";
|
||||
export { generateCliReference } from "./cli-reference.js";
|
||||
export { generateDeveloperReference } from "./developer-reference.js";
|
||||
export { env } from "./env.js";
|
||||
export type {
|
||||
AgentFrontmatter,
|
||||
|
||||
Reference in New Issue
Block a user