@vsem/ai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -0
- package/bin/cli.js +177 -0
- package/package.json +25 -0
- package/templates/scaffold/.ai/decisions/_index.md +3 -0
- package/templates/scaffold/.ai/incidents/_index.md +3 -0
- package/templates/scaffold/.ai/index/README.md +3 -0
- package/templates/scaffold/.ai/plan.md.tmpl +8 -0
- package/templates/scaffold/.ai/project.md.tmpl +17 -0
- package/templates/scaffold/.ai/tasks/_index.md +8 -0
- package/templates/system/.ai/roles/architect.md +14 -0
- package/templates/system/.ai/roles/context-manager.md +14 -0
- package/templates/system/.ai/roles/conventions-guardian.md +14 -0
- package/templates/system/.ai/roles/designer.md +14 -0
- package/templates/system/.ai/roles/developer.md +14 -0
- package/templates/system/.ai/roles/indexer-librarian.md +14 -0
- package/templates/system/.ai/roles/project-manager.md +14 -0
- package/templates/system/.ai/roles/reviewer-qa.md +14 -0
- package/templates/system/.ai/roles/technical-writer.md +14 -0
- package/templates/system/.ai/roles/tester.md +14 -0
- package/templates/system/.ai/rules/core.md +28 -0
- package/templates/system/.ai/rules/tasks-format.md +36 -0
- package/templates/system/CLAUDE.md.tmpl +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @vsem/ai
|
|
2
|
+
|
|
3
|
+
Install or sync a vsem-framework workspace: creates `.ai/` (rules, roles, tasks,
|
|
4
|
+
decisions, incidents, index), `CLAUDE.md`, `code/`, `materials/`, and sets up git
|
|
5
|
+
with your personal branch.
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd my-project
|
|
11
|
+
npx @vsem/ai@latest
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Runs against the current directory by default. Optional arguments:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx @vsem/ai@latest [target-dir] [--branch <name>] [--force]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- `target-dir` — install into this directory instead of the current one (created if missing).
|
|
21
|
+
- `--branch <name>` — personal branch name (default: your `git config --global user.name`, or `dev`).
|
|
22
|
+
- `--force` — also overwrite project-owned files (`.ai/project.md`, `.ai/plan.md`, task/decision/incident indexes), resetting them to placeholders. Without this flag, reruns only update framework-owned files (`.ai/rules/`, `.ai/roles/`, `CLAUDE.md`) and never touch your own project state.
|
|
23
|
+
|
|
24
|
+
## Updating an existing workspace
|
|
25
|
+
|
|
26
|
+
Rerun `npx @vsem/ai@latest` (without `--force`) inside an already-bootstrapped
|
|
27
|
+
workspace to pick up new roles or rule changes published in later versions — your
|
|
28
|
+
`project.md`, `plan.md`, and tasks are left untouched.
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Install or sync a vsem-framework workspace.
|
|
5
|
+
//
|
|
6
|
+
// This script contains NO framework content (no role text, no rule text). It only
|
|
7
|
+
// knows HOW to install the structure: it copies two template trees from
|
|
8
|
+
// ../templates next to this script into the target workspace, substituting
|
|
9
|
+
// {{VAR}} placeholders, and sets up git.
|
|
10
|
+
//
|
|
11
|
+
// - templates/system/ -> framework-owned files (CLAUDE.md, .ai/rules/*, .ai/roles/*).
|
|
12
|
+
// Always re-copied (overwritten) on every run. To add a new role, drop a file under
|
|
13
|
+
// templates/system/.ai/roles/, bump the package version and publish - no code
|
|
14
|
+
// change needed here.
|
|
15
|
+
// - templates/scaffold/ -> project-owned starting points (.ai/project.md, .ai/plan.md,
|
|
16
|
+
// .ai/tasks/_index.md, etc). Only written if missing, so a rerun never clobbers the
|
|
17
|
+
// user's own project state. Pass --force to overwrite scaffold files too.
|
|
18
|
+
//
|
|
19
|
+
// Usage:
|
|
20
|
+
// npx @vsem/ai@latest [target-dir] [--branch <name>] [--force]
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const { execFileSync } = require('child_process');
|
|
25
|
+
|
|
26
|
+
const FRAMEWORK_VERSION = '0.1.0';
|
|
27
|
+
const PACKAGE_DIR = path.join(__dirname, '..');
|
|
28
|
+
const TEMPLATES_DIR = path.join(PACKAGE_DIR, 'templates');
|
|
29
|
+
const SYSTEM_DIR = path.join(TEMPLATES_DIR, 'system');
|
|
30
|
+
const SCAFFOLD_DIR = path.join(TEMPLATES_DIR, 'scaffold');
|
|
31
|
+
|
|
32
|
+
function parseArgs(argv) {
|
|
33
|
+
const opts = { target: null, branch: null, force: false };
|
|
34
|
+
for (let i = 0; i < argv.length; i++) {
|
|
35
|
+
const a = argv[i];
|
|
36
|
+
if (a === '--force') {
|
|
37
|
+
opts.force = true;
|
|
38
|
+
} else if (a === '--branch') {
|
|
39
|
+
opts.branch = argv[++i] || null;
|
|
40
|
+
} else if (a.startsWith('--branch=')) {
|
|
41
|
+
opts.branch = a.slice('--branch='.length);
|
|
42
|
+
} else if (!a.startsWith('-') && opts.target === null) {
|
|
43
|
+
opts.target = a;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return opts;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function walkFiles(dir) {
|
|
50
|
+
const results = [];
|
|
51
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
52
|
+
const full = path.join(dir, entry.name);
|
|
53
|
+
if (entry.isDirectory()) {
|
|
54
|
+
results.push(...walkFiles(full));
|
|
55
|
+
} else if (entry.isFile()) {
|
|
56
|
+
results.push(full);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return results;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Copies every file under srcRoot into destRoot, preserving relative paths.
|
|
63
|
+
// Strips a trailing ".tmpl" from destination file names. Replaces {{KEY}}
|
|
64
|
+
// tokens. Only overwrites existing destination files when overwrite is true;
|
|
65
|
+
// otherwise leaves them untouched (used for scaffold/ files).
|
|
66
|
+
function copyTemplateTree(srcRoot, destRoot, vars, overwrite) {
|
|
67
|
+
if (!fs.existsSync(srcRoot)) return;
|
|
68
|
+
for (const file of walkFiles(srcRoot)) {
|
|
69
|
+
let rel = path.relative(srcRoot, file);
|
|
70
|
+
if (rel.endsWith('.tmpl')) {
|
|
71
|
+
rel = rel.slice(0, -'.tmpl'.length);
|
|
72
|
+
}
|
|
73
|
+
const dest = path.join(destRoot, rel);
|
|
74
|
+
|
|
75
|
+
if (fs.existsSync(dest) && !overwrite) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
80
|
+
let content = fs.readFileSync(file, 'utf8');
|
|
81
|
+
for (const key of Object.keys(vars)) {
|
|
82
|
+
content = content.split(`{{${key}}}`).join(vars[key]);
|
|
83
|
+
}
|
|
84
|
+
fs.writeFileSync(dest, content, 'utf8');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function ensureEmptyDirPlaceholder(dir) {
|
|
89
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
90
|
+
if (fs.readdirSync(dir).length === 0) {
|
|
91
|
+
fs.writeFileSync(path.join(dir, '.gitkeep'), '');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function tryGit(args, cwd) {
|
|
96
|
+
try {
|
|
97
|
+
return { ok: true, out: execFileSync('git', args, { cwd, encoding: 'utf8' }) };
|
|
98
|
+
} catch (err) {
|
|
99
|
+
return { ok: false, out: '', err };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function main() {
|
|
104
|
+
if (!fs.existsSync(SYSTEM_DIR)) {
|
|
105
|
+
console.error(`Templates not found at ${SYSTEM_DIR}. This script must ship together with templates/.`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const args = parseArgs(process.argv.slice(2));
|
|
110
|
+
const target = path.resolve(args.target || process.cwd());
|
|
111
|
+
|
|
112
|
+
fs.mkdirSync(target, { recursive: true });
|
|
113
|
+
const aiDir = path.join(target, '.ai');
|
|
114
|
+
const workspaceName = path.basename(target);
|
|
115
|
+
const isRerun = fs.existsSync(aiDir);
|
|
116
|
+
|
|
117
|
+
let branch = args.branch;
|
|
118
|
+
if (!branch) {
|
|
119
|
+
const cfg = tryGit(['config', '--global', 'user.name'], target);
|
|
120
|
+
if (cfg.ok && cfg.out.trim()) {
|
|
121
|
+
branch = cfg.out.trim().toLowerCase().replace(/\s+/g, '-').replace(/^-+|-+$/g, '');
|
|
122
|
+
}
|
|
123
|
+
if (!branch) branch = 'dev';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const vars = { WORKSPACE_NAME: workspaceName, FRAMEWORK_VERSION: FRAMEWORK_VERSION };
|
|
127
|
+
|
|
128
|
+
copyTemplateTree(SYSTEM_DIR, target, vars, true);
|
|
129
|
+
copyTemplateTree(SCAFFOLD_DIR, target, vars, args.force);
|
|
130
|
+
|
|
131
|
+
for (const rel of ['code', 'materials', path.join('.ai', 'memory')]) {
|
|
132
|
+
ensureEmptyDirPlaceholder(path.join(target, rel));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (isRerun) {
|
|
136
|
+
console.log(`[ok] Workspace synced at ${target} (system files updated; scaffold files kept unless --force)`);
|
|
137
|
+
} else {
|
|
138
|
+
console.log(`[ok] Workspace structure created at ${target}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const gitCheck = tryGit(['--version'], target);
|
|
142
|
+
if (!gitCheck.ok) {
|
|
143
|
+
console.log('[warn] git not found in PATH - skipping git init.');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!fs.existsSync(path.join(target, '.git'))) {
|
|
148
|
+
tryGit(['init', '-q'], target);
|
|
149
|
+
console.log('[ok] git init');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const currentBranchResult = tryGit(['branch', '--show-current'], target);
|
|
153
|
+
const currentBranch = currentBranchResult.ok ? currentBranchResult.out.trim() : '';
|
|
154
|
+
|
|
155
|
+
if (currentBranch !== branch) {
|
|
156
|
+
const branchExists = tryGit(['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], target).ok;
|
|
157
|
+
if (branchExists) {
|
|
158
|
+
tryGit(['checkout', '-q', branch], target);
|
|
159
|
+
} else {
|
|
160
|
+
tryGit(['checkout', '-q', '-b', branch], target);
|
|
161
|
+
}
|
|
162
|
+
console.log(`[ok] branch '${branch}' is active`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
tryGit(['add', '-A'], target);
|
|
166
|
+
const noChanges = tryGit(['diff', '--cached', '--quiet'], target).ok;
|
|
167
|
+
|
|
168
|
+
if (!noChanges) {
|
|
169
|
+
const msg = isRerun ? 'chore: sync vsem-framework system files' : 'chore: bootstrap vsem-framework workspace';
|
|
170
|
+
tryGit(['commit', '-q', '-m', msg], target);
|
|
171
|
+
console.log(`[ok] commit created: ${msg}`);
|
|
172
|
+
} else {
|
|
173
|
+
console.log('[skip] nothing to commit (already up to date)');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vsem/ai",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Install or sync a vsem-framework workspace (.ai/ structure, roles, rules) via npx.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"vsem-ai": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin",
|
|
10
|
+
"templates"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=14"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"license": "UNLICENSED",
|
|
19
|
+
"keywords": [
|
|
20
|
+
"ai",
|
|
21
|
+
"framework",
|
|
22
|
+
"scaffolding",
|
|
23
|
+
"claude"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Project - {{WORKSPACE_NAME}}
|
|
2
|
+
|
|
3
|
+
> TODO: filled in by the PM role after a requirements dialogue with the user
|
|
4
|
+
> (goal, audience, constraints, MVP scope). Source material - see `materials/`.
|
|
5
|
+
|
|
6
|
+
## Vision
|
|
7
|
+
TODO
|
|
8
|
+
|
|
9
|
+
## Goals
|
|
10
|
+
TODO
|
|
11
|
+
|
|
12
|
+
## Non-goals
|
|
13
|
+
TODO
|
|
14
|
+
|
|
15
|
+
## Key decisions log
|
|
16
|
+
| Date | Decision | Reason |
|
|
17
|
+
|------|----------|--------|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Tasks Index
|
|
2
|
+
|
|
3
|
+
> Auto-generated summary of `.ai/tasks/*.md`, so roles don't need to read every
|
|
4
|
+
> file - saves tokens (see the ContextManager role). Task format - see
|
|
5
|
+
> `.ai/rules/tasks-format.md`.
|
|
6
|
+
|
|
7
|
+
| id | title | owner_role | status | priority |
|
|
8
|
+
|----|-------|------------|--------|----------|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: architect
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Architect
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Architectural and technical decisions at project/module level.
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
Developer (until the decision is reconsidered).
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
The decision is irreversible or affects multiple code repositories at once.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: context-manager
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# ContextManager (system role)
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Assembles the minimally sufficient context for a role+task (token economy).
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
-
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
Session token budget is at risk of being exceeded.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: conventions-guardian
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# ConventionsGuardian
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Checks that code/documents comply with framework conventions; guards the hard rule "never change .ai/ structure without confirmation".
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
Any role, if it violates the .ai/ structure or conventions.
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
A violation of .ai/ structure is found - escalate immediately, without attempting to fix it itself.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: developer
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Developer
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Implementation of code in code/* per task.
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
-
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
The task is ambiguous and requires an architectural decision that does not exist yet.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: indexer-librarian
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Indexer/Librarian
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Maintains the document/code index/graph in .ai/index/ (exact mechanism still being designed).
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
-
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
Found a contradiction between documents it cannot resolve on its own.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: project-manager
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# ProjectManager (PM)
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Task decomposition and prioritization (incrementally, as the project progresses), final decision in role conflicts, maintaining the decision log, distributing work across roles.
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
Can pause any role in case of priority conflicts.
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
Not confident in resolving the conflict itself; the question affects MVP scope/deadlines.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: reviewer-qa
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Reviewer/QA
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Quality check of task results before closing (tests, linter, review).
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
Developer (task stays open until the gate is passed).
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
The found issue is systemic (not scoped to a single task).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: technical-writer
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# TechnicalWriter
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Documentation for humans (README, guides) outside .ai/ - inside .ai/ the structure itself is the documentation.
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
-
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
Not enough information from other roles to describe the feature.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
role_id: tester
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Tester
|
|
6
|
+
|
|
7
|
+
## Responsible for
|
|
8
|
+
Test scenarios and running them (may overlap with Reviewer/QA - the split is refined as the project evolves).
|
|
9
|
+
|
|
10
|
+
## Can block
|
|
11
|
+
-
|
|
12
|
+
|
|
13
|
+
## Escalates to the human when
|
|
14
|
+
Cannot reproduce/confirm the bug.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
framework_version: "{{FRAMEWORK_VERSION}}"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Core Rules (vsem-framework)
|
|
6
|
+
|
|
7
|
+
1. **Never change the structure of `.ai/`** (create/delete/rename top-level
|
|
8
|
+
folders inside it) without explicit human confirmation. This is the main rule
|
|
9
|
+
for every role/agent working in this workspace.
|
|
10
|
+
2. Roles work within a limited, role-scoped context - do not read the whole
|
|
11
|
+
repository unless the task requires it. Context for a task is assembled by
|
|
12
|
+
ContextManager.
|
|
13
|
+
3. Conflicts between roles are resolved by ProjectManager; the decision is
|
|
14
|
+
recorded in `.ai/decisions/`. If PM itself is not sure, escalate to the human.
|
|
15
|
+
4. Autonomy by default - the framework acts on its own. Stop and ask the human
|
|
16
|
+
when:
|
|
17
|
+
- about to merge the personal branch into `main`;
|
|
18
|
+
- the operation deletes data or is irreversible;
|
|
19
|
+
- an external access/secret/integration is required;
|
|
20
|
+
- the decision is architectural at the whole-project level;
|
|
21
|
+
- the role itself is not sure about the decision.
|
|
22
|
+
5. In autonomous mode, commits go to the user's personal branch, never to `main`.
|
|
23
|
+
6. `code/*` is code only (git submodules). `materials/` is raw input from the
|
|
24
|
+
user. `.ai/` holds the entire methodology and working state of the project.
|
|
25
|
+
7. A task is not closed (`status: done`) without passing its quality gate, if
|
|
26
|
+
one is required for it (see `.ai/roles/reviewer-qa.md`).
|
|
27
|
+
|
|
28
|
+
See also `.ai/project.md` (this project's description) and `.ai/plan.md` (this project's plan).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Task Format
|
|
2
|
+
|
|
3
|
+
One file = one task, in `.ai/tasks/`. File name: `<id>-<short-slug>.md`
|
|
4
|
+
(id = zero-padded sequence number, e.g. `0001`).
|
|
5
|
+
|
|
6
|
+
## Frontmatter
|
|
7
|
+
|
|
8
|
+
```yaml
|
|
9
|
+
---
|
|
10
|
+
id: "0001"
|
|
11
|
+
title: "Short task title"
|
|
12
|
+
owner_role: developer # one of the roles in .ai/roles/, lowercase
|
|
13
|
+
status: todo # todo | in_progress | blocked-on-human | blocked-on-dependency | blocked-on-external | in_review | done
|
|
14
|
+
priority: must # must | nice
|
|
15
|
+
depends_on: [] # ids of blocking tasks, e.g. ["0002"]
|
|
16
|
+
linked_files: # paths to files/modules this task touches
|
|
17
|
+
- code/backend/src/auth/
|
|
18
|
+
created: YYYY-MM-DD
|
|
19
|
+
updated: YYYY-MM-DD
|
|
20
|
+
---
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Body
|
|
24
|
+
- **Description** - what needs to be done and why.
|
|
25
|
+
- **Acceptance criteria** - short checklist Reviewer/QA uses to confirm the task is done.
|
|
26
|
+
- **Notes** - optional work log.
|
|
27
|
+
|
|
28
|
+
## Status transitions
|
|
29
|
+
`todo -> in_progress -> in_review -> done`
|
|
30
|
+
Side branches: `blocked-on-*` (from any active status, back to `in_progress` once unblocked).
|
|
31
|
+
|
|
32
|
+
## Who sets what
|
|
33
|
+
- `priority` - ProjectManager.
|
|
34
|
+
- `owner_role` - ProjectManager, during decomposition.
|
|
35
|
+
- `status` - the owning role, as work progresses; moving to `done` requires
|
|
36
|
+
passing the quality gate (Reviewer/QA) if one applies to the task.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# {{WORKSPACE_NAME}}
|
|
2
|
+
|
|
3
|
+
This project is managed by vsem-framework.
|
|
4
|
+
Work according to the rules and structure in `.ai/`.
|
|
5
|
+
Start with `.ai/rules/core.md` and `.ai/project.md`.
|
|
6
|
+
|
|
7
|
+
**Hard rule:** never modify the top-level structure of `.ai/` (create/delete/rename
|
|
8
|
+
top-level folders inside it) without explicit human confirmation.
|