@pedrocivita/tocket 1.0.0 → 1.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 +91 -19
- package/dist/commands/generate.cmd.js +17 -52
- package/dist/commands/init.cmd.js +5 -1
- package/dist/commands/validate.cmd.d.ts +2 -0
- package/dist/commands/validate.cmd.js +90 -0
- package/dist/index.js +3 -1
- package/dist/templates/memory-bank.d.ts +4 -0
- package/dist/templates/memory-bank.js +170 -5
- package/dist/tests/memory-bank.test.d.ts +1 -0
- package/dist/tests/memory-bank.test.js +132 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,38 +1,110 @@
|
|
|
1
|
+

|
|
2
|
+
[](https://www.npmjs.com/package/@pedrocivita/tocket)
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
|
|
1
5
|
# Tocket
|
|
2
6
|
|
|
3
7
|
**The Context Engineering Framework for Multi-Agent Workspaces**
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
When multiple AI agents work on the same codebase, context is lost between sessions and between agents. Each one starts from scratch, re-reads files, and makes decisions that conflict with previous ones.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
Tocket fixes this with two primitives:
|
|
8
12
|
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
13
|
+
- **Memory Bank** — A `.context/` directory with version-controlled markdown files that any AI can read. The project's ground truth lives in files, not in chat history.
|
|
14
|
+
- **Triangulation** — An Architect plans, an Executor implements, and structured XML payloads are the handoff between them.
|
|
11
15
|
|
|
12
|
-
##
|
|
16
|
+
## Who is this for?
|
|
17
|
+
|
|
18
|
+
- Developers using **multi-agent setups** (Gemini + Claude, Cursor + Copilot, etc.)
|
|
19
|
+
- Teams that want **reproducible AI-assisted development** across sessions
|
|
20
|
+
- Anyone tired of re-explaining project context to AI every time they open a chat
|
|
21
|
+
|
|
22
|
+
## You don't need the CLI to use Tocket
|
|
13
23
|
|
|
14
|
-
|
|
15
|
-
|---------|-------------|
|
|
16
|
-
| `tocket init` | Scaffold an agentic workspace with Memory Bank and triangulation config |
|
|
17
|
-
| `tocket generate` | Build payload XMLs interactively for Architect-Executor handoff |
|
|
18
|
-
| `tocket sync` | Update Memory Bank from git history and session artifacts |
|
|
24
|
+
The protocol is just files. You can adopt it manually:
|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
1. Create a `.context/` directory with `activeContext.md` and `systemPatterns.md`
|
|
27
|
+
2. Add a `TOCKET.md` to your repo root (see [the spec](TOCKET.md))
|
|
28
|
+
3. Tell your AI agents to read `.context/` before acting
|
|
29
|
+
|
|
30
|
+
The CLI just automates the scaffolding.
|
|
31
|
+
|
|
32
|
+
## Quick Start
|
|
21
33
|
|
|
22
34
|
```bash
|
|
23
|
-
|
|
35
|
+
# Scaffold a new workspace (creates .context/, TOCKET.md, CLAUDE.md, GEMINI.md)
|
|
36
|
+
npx @pedrocivita/tocket init
|
|
37
|
+
|
|
38
|
+
# Generate a payload XML for agent handoff
|
|
39
|
+
npx @pedrocivita/tocket generate
|
|
40
|
+
|
|
41
|
+
# Sync session progress into Memory Bank
|
|
42
|
+
npx @pedrocivita/tocket sync
|
|
24
43
|
```
|
|
25
44
|
|
|
26
|
-
##
|
|
45
|
+
## Commands
|
|
27
46
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
47
|
+
| Command | What it does |
|
|
48
|
+
| ----------------- | -------------------------------------------------------------- |
|
|
49
|
+
| `tocket init` | Scaffolds `.context/`, `TOCKET.md`, `CLAUDE.md`, `GEMINI.md` |
|
|
50
|
+
| `tocket generate` | Interactive payload XML builder — copies to clipboard |
|
|
51
|
+
| `tocket sync` | Appends session summary + git log to `.context/progress.md` |
|
|
52
|
+
| `tocket validate` | Checks if the current directory has a valid Tocket Memory Bank |
|
|
53
|
+
|
|
54
|
+
## How Triangulation works
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
Architect (any planning AI) Executor (any coding AI)
|
|
58
|
+
│ │
|
|
59
|
+
│ 1. Reads .context/ │
|
|
60
|
+
│ 2. Analyzes task │
|
|
61
|
+
│ 3. Generates <payload> XML │
|
|
62
|
+
│──────── structured handoff ──────►│
|
|
63
|
+
│ │ 4. Reads .context/ + payload
|
|
64
|
+
│ │ 5. Implements tasks
|
|
65
|
+
│ │ 6. Updates .context/
|
|
66
|
+
│◄──────── status report ───────────│
|
|
34
67
|
```
|
|
35
68
|
|
|
69
|
+
The Architect doesn't write code. The Executor doesn't make architecture decisions. The payload is the contract between them.
|
|
70
|
+
|
|
71
|
+
## Memory Bank files
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
.context/
|
|
75
|
+
activeContext.md ← Current focus. Read this first.
|
|
76
|
+
systemPatterns.md ← Architecture decisions and conventions.
|
|
77
|
+
techContext.md ← Stack, build tools, critical rules.
|
|
78
|
+
productContext.md ← What the product is and why it exists.
|
|
79
|
+
progress.md ← What's done, what's next.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
All files are markdown. All files are committed to git. Any AI that can read files can participate.
|
|
83
|
+
|
|
84
|
+
## Documentation
|
|
85
|
+
|
|
86
|
+
| Guide | Description |
|
|
87
|
+
| ------------------------------------------- | ----------------------------------------------- |
|
|
88
|
+
| [Getting Started](docs/GETTING_STARTED.md) | Set up your first Tocket workspace in 5 minutes |
|
|
89
|
+
| [Tocket Rules](docs/TOCKET_RULES.md) | Complete reference for all protocol rules |
|
|
90
|
+
| [Developer Guide](docs/DEVELOPERS_GUIDE.md) | Contributing to the Tocket CLI codebase |
|
|
91
|
+
| [Protocol Spec](TOCKET.md) | The agent-agnostic protocol specification |
|
|
92
|
+
|
|
93
|
+
## How is this different from...
|
|
94
|
+
|
|
95
|
+
| Tool | What it does | How Tocket differs |
|
|
96
|
+
| ---------------- | ------------------------------------ | ------------------------------------------------------------------------------------ |
|
|
97
|
+
| `.cursorrules` | Single-agent instructions for Cursor | Tocket defines _inter-agent_ protocol, not just single-agent rules |
|
|
98
|
+
| `CLAUDE.md` | Instructions for Claude Code | Tocket generates `CLAUDE.md` _as part of_ a broader multi-agent system |
|
|
99
|
+
| `AGENTS.md` | Codex agent instructions | Same idea for one agent; Tocket coordinates multiple agents |
|
|
100
|
+
| Prompt templates | Static prompts for LLMs | Tocket's Memory Bank evolves with the project; payloads are structured, not freeform |
|
|
101
|
+
|
|
102
|
+
## Contributing
|
|
103
|
+
|
|
104
|
+
We welcome contributions! Please read our [Contributing Guide](CONTRIBUTING.md) to get started.
|
|
105
|
+
|
|
106
|
+
This project follows a [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
107
|
+
|
|
36
108
|
## License
|
|
37
109
|
|
|
38
110
|
MIT
|
|
@@ -1,43 +1,31 @@
|
|
|
1
|
-
import { input, select
|
|
1
|
+
import { input, select } from "@inquirer/prompts";
|
|
2
2
|
import clipboard from "clipboardy";
|
|
3
|
-
function inferMode(score) {
|
|
4
|
-
if (score <= 6)
|
|
5
|
-
return "solo";
|
|
6
|
-
if (score <= 10)
|
|
7
|
-
return "team-small";
|
|
8
|
-
return "team-full";
|
|
9
|
-
}
|
|
10
3
|
function buildPayloadXml(opts) {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.filter(Boolean)
|
|
16
|
-
.map((s) => ` <skill>${s}</skill>`)
|
|
17
|
-
.join("\n");
|
|
18
|
-
return `<payload version="3.0">
|
|
4
|
+
const skillsAttr = opts.skills.trim()
|
|
5
|
+
? `\n <skills>${opts.skills.trim()}</skills>`
|
|
6
|
+
: "";
|
|
7
|
+
return `<payload version="2.0">
|
|
19
8
|
<meta>
|
|
20
9
|
<intent>${opts.intent}</intent>
|
|
21
|
-
<scope>${opts.scope}</scope
|
|
10
|
+
<scope>${opts.scope}</scope>${skillsAttr}
|
|
22
11
|
<priority>${opts.priority}</priority>
|
|
23
|
-
<complexity score="${opts.complexity}" mode="${mode}" />
|
|
24
|
-
<model>${opts.model}</model>
|
|
25
12
|
</meta>
|
|
26
13
|
|
|
27
|
-
<skills>
|
|
28
|
-
${skillLines || " <!-- Add skills here -->"}
|
|
29
|
-
</skills>
|
|
30
|
-
|
|
31
14
|
<context>
|
|
32
|
-
|
|
15
|
+
<summary><!-- Background and reasoning --></summary>
|
|
33
16
|
</context>
|
|
34
17
|
|
|
35
18
|
<tasks>
|
|
36
|
-
|
|
19
|
+
<task id="1" type="create | edit | delete">
|
|
20
|
+
<target><!-- file/path --></target>
|
|
21
|
+
<action><!-- What to do --></action>
|
|
22
|
+
<spec><!-- Detailed specification --></spec>
|
|
23
|
+
<done><!-- Definition of done --></done>
|
|
24
|
+
</task>
|
|
37
25
|
</tasks>
|
|
38
26
|
|
|
39
27
|
<validate>
|
|
40
|
-
|
|
28
|
+
<check><!-- How to verify success --></check>
|
|
41
29
|
</validate>
|
|
42
30
|
</payload>`;
|
|
43
31
|
}
|
|
@@ -57,33 +45,10 @@ export function registerGenerateCommand(program) {
|
|
|
57
45
|
],
|
|
58
46
|
});
|
|
59
47
|
const skills = await input({
|
|
60
|
-
message: "Skills/plugins (comma-separated):",
|
|
61
|
-
});
|
|
62
|
-
const model = await select({
|
|
63
|
-
message: "Architect model:",
|
|
64
|
-
choices: [
|
|
65
|
-
{
|
|
66
|
-
value: "gemini-3.1-pro-preview-customtools",
|
|
67
|
-
name: "gemini-3.1-pro-preview-customtools (default)",
|
|
68
|
-
},
|
|
69
|
-
{ value: "gemini-2.5-pro", name: "gemini-2.5-pro" },
|
|
70
|
-
],
|
|
71
|
-
});
|
|
72
|
-
const complexity = await number({
|
|
73
|
-
message: "Complexity score (0-15):",
|
|
74
|
-
min: 0,
|
|
75
|
-
max: 15,
|
|
76
|
-
required: true,
|
|
77
|
-
});
|
|
78
|
-
const xml = buildPayloadXml({
|
|
79
|
-
intent,
|
|
80
|
-
scope,
|
|
81
|
-
priority,
|
|
82
|
-
skills,
|
|
83
|
-
model,
|
|
84
|
-
complexity: complexity ?? 0,
|
|
48
|
+
message: "Skills/plugins (comma-separated, optional):",
|
|
85
49
|
});
|
|
50
|
+
const xml = buildPayloadXml({ intent, scope, priority, skills });
|
|
86
51
|
clipboard.writeSync(xml);
|
|
87
|
-
console.log("\n\x1b[32m
|
|
52
|
+
console.log("\n\x1b[32m\u2713\x1b[0m Payload XML (v2.0) copied to clipboard! Paste it into your Architect to continue.");
|
|
88
53
|
});
|
|
89
54
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { input } from "@inquirer/prompts";
|
|
2
2
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { claudeMd, geminiMd, activeContextMd, systemPatternsMd, } from "../templates/memory-bank.js";
|
|
4
|
+
import { claudeMd, geminiMd, tocketMd, activeContextMd, systemPatternsMd, productContextMd, techContextMd, progressMd, } from "../templates/memory-bank.js";
|
|
5
5
|
export function registerInitCommand(program) {
|
|
6
6
|
program
|
|
7
7
|
.command("init")
|
|
@@ -12,10 +12,14 @@ export function registerInitCommand(program) {
|
|
|
12
12
|
const contextDir = join(process.cwd(), ".context");
|
|
13
13
|
await mkdir(contextDir, { recursive: true });
|
|
14
14
|
const files = [
|
|
15
|
+
["TOCKET.md", tocketMd(projectName)],
|
|
15
16
|
["CLAUDE.md", claudeMd(projectName, description)],
|
|
16
17
|
["GEMINI.md", geminiMd(projectName, description)],
|
|
17
18
|
[join(".context", "activeContext.md"), activeContextMd(projectName)],
|
|
18
19
|
[join(".context", "systemPatterns.md"), systemPatternsMd(projectName)],
|
|
20
|
+
[join(".context", "productContext.md"), productContextMd(projectName, description)],
|
|
21
|
+
[join(".context", "techContext.md"), techContextMd(projectName)],
|
|
22
|
+
[join(".context", "progress.md"), progressMd(projectName)],
|
|
19
23
|
];
|
|
20
24
|
for (const [filePath, content] of files) {
|
|
21
25
|
const fullPath = join(process.cwd(), filePath);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { existsSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const PASS = "\x1b[32m\u2713\x1b[0m";
|
|
4
|
+
const WARN = "\x1b[33m\u26A0\x1b[0m";
|
|
5
|
+
const FAIL = "\x1b[31m\u2717\x1b[0m";
|
|
6
|
+
function checkFile(basePath, relativePath, required) {
|
|
7
|
+
const fullPath = join(basePath, relativePath);
|
|
8
|
+
if (existsSync(fullPath)) {
|
|
9
|
+
return { icon: PASS, message: `${relativePath} found` };
|
|
10
|
+
}
|
|
11
|
+
if (required) {
|
|
12
|
+
return { icon: FAIL, message: `${relativePath} missing (required)` };
|
|
13
|
+
}
|
|
14
|
+
return { icon: WARN, message: `${relativePath} missing (optional)` };
|
|
15
|
+
}
|
|
16
|
+
function checkStale(basePath, relativePath) {
|
|
17
|
+
const fullPath = join(basePath, relativePath);
|
|
18
|
+
if (!existsSync(fullPath))
|
|
19
|
+
return null;
|
|
20
|
+
const stats = statSync(fullPath);
|
|
21
|
+
const daysSinceModified = Math.floor((Date.now() - stats.mtimeMs) / (1000 * 60 * 60 * 24));
|
|
22
|
+
if (daysSinceModified > 7) {
|
|
23
|
+
return {
|
|
24
|
+
icon: WARN,
|
|
25
|
+
message: `${relativePath} last modified ${daysSinceModified} days ago (may be stale)`,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
function checkAgentFile(basePath) {
|
|
31
|
+
const agentFiles = [
|
|
32
|
+
"CLAUDE.md",
|
|
33
|
+
"GEMINI.md",
|
|
34
|
+
"EXECUTOR.md",
|
|
35
|
+
"ARCHITECT.md",
|
|
36
|
+
".cursorrules",
|
|
37
|
+
];
|
|
38
|
+
const found = agentFiles.filter((f) => existsSync(join(basePath, f)));
|
|
39
|
+
if (found.length > 0) {
|
|
40
|
+
return {
|
|
41
|
+
icon: PASS,
|
|
42
|
+
message: `Agent config found: ${found.join(", ")}`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
icon: WARN,
|
|
47
|
+
message: "No agent config file found (CLAUDE.md, GEMINI.md, etc.)",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function registerValidateCommand(program) {
|
|
51
|
+
program
|
|
52
|
+
.command("validate")
|
|
53
|
+
.description("Check the health of a Tocket workspace")
|
|
54
|
+
.action(() => {
|
|
55
|
+
const cwd = process.cwd();
|
|
56
|
+
const results = [];
|
|
57
|
+
let hasFailure = false;
|
|
58
|
+
console.log("\nValidating Tocket workspace...\n");
|
|
59
|
+
// Required files
|
|
60
|
+
results.push(checkFile(cwd, join(".context"), true));
|
|
61
|
+
results.push(checkFile(cwd, join(".context", "activeContext.md"), true));
|
|
62
|
+
results.push(checkFile(cwd, join(".context", "systemPatterns.md"), true));
|
|
63
|
+
results.push(checkFile(cwd, "TOCKET.md", true));
|
|
64
|
+
// Optional files
|
|
65
|
+
results.push(checkFile(cwd, join(".context", "techContext.md"), false));
|
|
66
|
+
results.push(checkFile(cwd, join(".context", "productContext.md"), false));
|
|
67
|
+
results.push(checkFile(cwd, join(".context", "progress.md"), false));
|
|
68
|
+
// Agent config
|
|
69
|
+
results.push(checkAgentFile(cwd));
|
|
70
|
+
// Staleness check
|
|
71
|
+
const staleCheck = checkStale(cwd, join(".context", "activeContext.md"));
|
|
72
|
+
if (staleCheck) {
|
|
73
|
+
results.push(staleCheck);
|
|
74
|
+
}
|
|
75
|
+
// Print results
|
|
76
|
+
for (const r of results) {
|
|
77
|
+
console.log(` ${r.icon} ${r.message}`);
|
|
78
|
+
if (r.icon === FAIL)
|
|
79
|
+
hasFailure = true;
|
|
80
|
+
}
|
|
81
|
+
console.log("");
|
|
82
|
+
if (hasFailure) {
|
|
83
|
+
console.log("\x1b[31mWorkspace has issues.\x1b[0m Run \x1b[1mtocket init\x1b[0m to scaffold missing files.");
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log("\x1b[32mWorkspace is healthy.\x1b[0m");
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -3,12 +3,14 @@ import { Command } from "commander";
|
|
|
3
3
|
import { registerInitCommand } from "./commands/init.cmd.js";
|
|
4
4
|
import { registerGenerateCommand } from "./commands/generate.cmd.js";
|
|
5
5
|
import { registerSyncCommand } from "./commands/sync.cmd.js";
|
|
6
|
+
import { registerValidateCommand } from "./commands/validate.cmd.js";
|
|
6
7
|
const program = new Command();
|
|
7
8
|
program
|
|
8
9
|
.name("tocket")
|
|
9
10
|
.description("The Context Engineering Framework for Multi-Agent Workspaces")
|
|
10
|
-
.version("1.
|
|
11
|
+
.version("1.1.0");
|
|
11
12
|
registerInitCommand(program);
|
|
12
13
|
registerGenerateCommand(program);
|
|
13
14
|
registerSyncCommand(program);
|
|
15
|
+
registerValidateCommand(program);
|
|
14
16
|
program.parse();
|
|
@@ -2,3 +2,7 @@ export declare const claudeMd: (projectName: string, description: string) => str
|
|
|
2
2
|
export declare const geminiMd: (projectName: string, description: string) => string;
|
|
3
3
|
export declare const activeContextMd: (projectName: string) => string;
|
|
4
4
|
export declare const systemPatternsMd: (projectName: string) => string;
|
|
5
|
+
export declare const productContextMd: (projectName: string, description: string) => string;
|
|
6
|
+
export declare const techContextMd: (projectName: string) => string;
|
|
7
|
+
export declare const progressMd: (projectName: string) => string;
|
|
8
|
+
export declare const tocketMd: (projectName: string) => string;
|
|
@@ -53,7 +53,7 @@ Your job is to **analyze, plan, and decide**. You do not write code directly —
|
|
|
53
53
|
## Rules
|
|
54
54
|
|
|
55
55
|
1. **Read \`.context/\` first** — Understand current state before planning.
|
|
56
|
-
2. **Produce
|
|
56
|
+
2. **Produce payloads** — Use \`<payload version="2.0">\` XML format for handoff to the Executor.
|
|
57
57
|
3. **Never write code inline** — Provide specs, not implementations. The Executor handles code.
|
|
58
58
|
4. **Update systemPatterns.md** — When you make architectural decisions, record them.
|
|
59
59
|
5. **Think in constraints** — Define what the system should and should not do.
|
|
@@ -70,12 +70,12 @@ Your job is to **analyze, plan, and decide**. You do not write code directly —
|
|
|
70
70
|
|
|
71
71
|
---
|
|
72
72
|
|
|
73
|
-
##
|
|
73
|
+
## Payload Format
|
|
74
74
|
|
|
75
75
|
\`\`\`xml
|
|
76
|
-
<
|
|
76
|
+
<payload version="2.0">
|
|
77
77
|
<meta>
|
|
78
|
-
<
|
|
78
|
+
<intent>What needs to happen</intent>
|
|
79
79
|
<scope>Which files/modules are affected</scope>
|
|
80
80
|
<priority>high | medium | low</priority>
|
|
81
81
|
</meta>
|
|
@@ -94,7 +94,7 @@ Your job is to **analyze, plan, and decide**. You do not write code directly —
|
|
|
94
94
|
<validate>
|
|
95
95
|
<check>Verification step</check>
|
|
96
96
|
</validate>
|
|
97
|
-
</
|
|
97
|
+
</payload>
|
|
98
98
|
\`\`\`
|
|
99
99
|
`;
|
|
100
100
|
export const activeContextMd = (projectName) => `# Active Context - ${projectName}
|
|
@@ -139,3 +139,168 @@ _To be defined._
|
|
|
139
139
|
|----------|-----------|------|
|
|
140
140
|
| Adopted Tocket triangulation | Structured multi-agent workflow | ${new Date().toISOString().split("T")[0]} |
|
|
141
141
|
`;
|
|
142
|
+
export const productContextMd = (projectName, description) => `# Product Context - ${projectName}
|
|
143
|
+
|
|
144
|
+
<!-- What the product is, who it's for, and why it exists. Updated by the Architect. -->
|
|
145
|
+
|
|
146
|
+
## What is ${projectName}?
|
|
147
|
+
|
|
148
|
+
${description || "_Describe your product here._"}
|
|
149
|
+
|
|
150
|
+
## Problem
|
|
151
|
+
|
|
152
|
+
_What problem does this project solve?_
|
|
153
|
+
|
|
154
|
+
## Solution
|
|
155
|
+
|
|
156
|
+
_How does it solve it?_
|
|
157
|
+
|
|
158
|
+
## Target Users
|
|
159
|
+
|
|
160
|
+
_Who is this for?_
|
|
161
|
+
|
|
162
|
+
## Design Principles
|
|
163
|
+
|
|
164
|
+
- _List the guiding principles for this project_
|
|
165
|
+
`;
|
|
166
|
+
export const techContextMd = (projectName) => `# Tech Context - ${projectName}
|
|
167
|
+
|
|
168
|
+
<!-- Stack, build tools, and critical rules. Updated by the Architect. -->
|
|
169
|
+
|
|
170
|
+
## Stack
|
|
171
|
+
|
|
172
|
+
| Layer | Technology | Notes |
|
|
173
|
+
|-------|-----------|-------|
|
|
174
|
+
| Language | | |
|
|
175
|
+
| Runtime | | |
|
|
176
|
+
| Build | | |
|
|
177
|
+
| Framework | | |
|
|
178
|
+
|
|
179
|
+
## Critical Rules
|
|
180
|
+
|
|
181
|
+
_Document any rules that agents must follow (e.g., import conventions, naming patterns)._
|
|
182
|
+
|
|
183
|
+
## Project Structure
|
|
184
|
+
|
|
185
|
+
\`\`\`
|
|
186
|
+
${projectName}/
|
|
187
|
+
src/ # Source code
|
|
188
|
+
.context/ # Memory Bank
|
|
189
|
+
\`\`\`
|
|
190
|
+
`;
|
|
191
|
+
export const progressMd = (projectName) => `# Progress Log - ${projectName}
|
|
192
|
+
|
|
193
|
+
<!-- Appended by tocket sync and manual updates -->
|
|
194
|
+
|
|
195
|
+
## Milestone: Project Initialization
|
|
196
|
+
|
|
197
|
+
**Status**: Complete
|
|
198
|
+
|
|
199
|
+
- [x] Agentic workspace scaffolded with Tocket CLI
|
|
200
|
+
- [x] Memory Bank initialized (\`.context/\`)
|
|
201
|
+
|
|
202
|
+
## Next Up
|
|
203
|
+
|
|
204
|
+
- [ ] _Define your first milestone here_
|
|
205
|
+
`;
|
|
206
|
+
export const tocketMd = (projectName) => `# Tocket Protocol Specification
|
|
207
|
+
|
|
208
|
+
> How any AI agent should operate in **${projectName}**.
|
|
209
|
+
|
|
210
|
+
This file is **agent-agnostic**. Whether you are Claude, Gemini, GPT, Cursor, Cline, Copilot, or any future AI — if you see this file, follow these rules.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 1. Memory Bank
|
|
215
|
+
|
|
216
|
+
Project context lives in \`.context/\`, not in chat history. **Read it before doing anything.**
|
|
217
|
+
|
|
218
|
+
\`\`\`
|
|
219
|
+
.context/
|
|
220
|
+
activeContext.md <- Start here. Current focus, recent changes, open decisions.
|
|
221
|
+
systemPatterns.md <- Architecture patterns, conventions, key decisions.
|
|
222
|
+
techContext.md <- Tech stack, build tools, critical rules.
|
|
223
|
+
productContext.md <- What the product is, who it's for, why it exists.
|
|
224
|
+
progress.md <- What's done, what's next.
|
|
225
|
+
\`\`\`
|
|
226
|
+
|
|
227
|
+
### Rules
|
|
228
|
+
|
|
229
|
+
- **Read before acting** — Always read \`activeContext.md\` and \`systemPatterns.md\` before your first action in a session.
|
|
230
|
+
- **Write before leaving** — Update \`activeContext.md\` with what changed after completing significant work.
|
|
231
|
+
- **Trust the files** — If \`.context/\` says the project uses ESM, it uses ESM. Don't second-guess documented decisions.
|
|
232
|
+
- **Don't duplicate** — Context belongs in \`.context/\`, not scattered in code comments or chat summaries.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## 2. Triangulation
|
|
237
|
+
|
|
238
|
+
Tocket separates **planning** from **implementation** across two agent roles:
|
|
239
|
+
|
|
240
|
+
\`\`\`
|
|
241
|
+
┌─────────────────┐ ┌─────────────────┐
|
|
242
|
+
│ ARCHITECT │ │ EXECUTOR │
|
|
243
|
+
│ (Planner) │ payload │ (Implementer) │
|
|
244
|
+
│ │─────────>│ │
|
|
245
|
+
│ Analyzes task │ │ Receives plan │
|
|
246
|
+
│ Designs approach│ │ Writes code │
|
|
247
|
+
│ Generates XML │ │ Runs tests │
|
|
248
|
+
│ Updates patterns│ │ Updates context │
|
|
249
|
+
└─────────────────┘ └─────────────────┘
|
|
250
|
+
\`\`\`
|
|
251
|
+
|
|
252
|
+
### Architect
|
|
253
|
+
|
|
254
|
+
- Reads \`.context/\` to understand current state
|
|
255
|
+
- Produces structured payloads (see Section 3) with clear tasks
|
|
256
|
+
- Makes architectural decisions and records them in \`systemPatterns.md\`
|
|
257
|
+
- **Does not write code** — only specs and constraints
|
|
258
|
+
|
|
259
|
+
### Executor
|
|
260
|
+
|
|
261
|
+
- Reads \`.context/\` and the Architect's payload
|
|
262
|
+
- Implements tasks exactly as specified
|
|
263
|
+
- Asks when the plan is unclear — does not improvise architecture
|
|
264
|
+
- Updates \`activeContext.md\` and \`progress.md\` after completing work
|
|
265
|
+
|
|
266
|
+
### Solo Mode
|
|
267
|
+
|
|
268
|
+
Not every task needs triangulation. For simple, well-defined changes, a single agent can act as both Architect and Executor. The Memory Bank rules still apply.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## 3. Payloads
|
|
273
|
+
|
|
274
|
+
A payload is the structured handoff from Architect to Executor.
|
|
275
|
+
|
|
276
|
+
### Minimal Example
|
|
277
|
+
|
|
278
|
+
\`\`\`xml
|
|
279
|
+
<payload version="2.0">
|
|
280
|
+
<meta>
|
|
281
|
+
<intent>Goal in one line</intent>
|
|
282
|
+
<scope>Files affected</scope>
|
|
283
|
+
<priority>high | medium | low</priority>
|
|
284
|
+
</meta>
|
|
285
|
+
<tasks>
|
|
286
|
+
<task id="1" type="create | edit | delete">
|
|
287
|
+
<target>file/path</target>
|
|
288
|
+
<action>What to do</action>
|
|
289
|
+
<done>Definition of done</done>
|
|
290
|
+
</task>
|
|
291
|
+
</tasks>
|
|
292
|
+
<validate>
|
|
293
|
+
<check>How to verify success</check>
|
|
294
|
+
</validate>
|
|
295
|
+
</payload>
|
|
296
|
+
\`\`\`
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Quick Start
|
|
301
|
+
|
|
302
|
+
1. Read this file (\`TOCKET.md\`)
|
|
303
|
+
2. Read \`.context/activeContext.md\` for current state
|
|
304
|
+
3. Read your role-specific config (\`CLAUDE.md\` or \`GEMINI.md\`)
|
|
305
|
+
4. Proceed with your task, following the Memory Bank rules above
|
|
306
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { claudeMd, geminiMd, tocketMd, activeContextMd, systemPatternsMd, productContextMd, techContextMd, progressMd, } from "../templates/memory-bank.js";
|
|
4
|
+
describe("claudeMd", () => {
|
|
5
|
+
const output = claudeMd("TestProject", "A test project");
|
|
6
|
+
it("includes the project name in the title", () => {
|
|
7
|
+
assert.ok(output.includes("# CLAUDE.md - TestProject"));
|
|
8
|
+
});
|
|
9
|
+
it("includes the description as a blockquote", () => {
|
|
10
|
+
assert.ok(output.includes("> A test project"));
|
|
11
|
+
});
|
|
12
|
+
it("defines the Executor role", () => {
|
|
13
|
+
assert.ok(output.includes("**Executor**"));
|
|
14
|
+
});
|
|
15
|
+
it("references the Memory Bank files", () => {
|
|
16
|
+
assert.ok(output.includes(".context/activeContext.md"));
|
|
17
|
+
assert.ok(output.includes(".context/systemPatterns.md"));
|
|
18
|
+
});
|
|
19
|
+
it("handles empty description gracefully", () => {
|
|
20
|
+
const noDesc = claudeMd("Foo", "");
|
|
21
|
+
assert.ok(noDesc.includes("# CLAUDE.md - Foo"));
|
|
22
|
+
assert.ok(!noDesc.includes("> \n"));
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe("geminiMd", () => {
|
|
26
|
+
const output = geminiMd("TestProject", "A test project");
|
|
27
|
+
it("includes the project name in the title", () => {
|
|
28
|
+
assert.ok(output.includes("# GEMINI.md - TestProject"));
|
|
29
|
+
});
|
|
30
|
+
it("defines the Architect role", () => {
|
|
31
|
+
assert.ok(output.includes("**Architect**"));
|
|
32
|
+
});
|
|
33
|
+
it("references payload v2.0 format", () => {
|
|
34
|
+
assert.ok(output.includes('<payload version="2.0">'));
|
|
35
|
+
});
|
|
36
|
+
it("does not reference the deprecated mission-brief format", () => {
|
|
37
|
+
assert.ok(!output.includes("<mission-brief"));
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("tocketMd", () => {
|
|
41
|
+
const output = tocketMd("TestProject");
|
|
42
|
+
it("includes the protocol title", () => {
|
|
43
|
+
assert.ok(output.includes("# Tocket Protocol Specification"));
|
|
44
|
+
});
|
|
45
|
+
it("includes the project name", () => {
|
|
46
|
+
assert.ok(output.includes("**TestProject**"));
|
|
47
|
+
});
|
|
48
|
+
it("declares agent-agnostic stance", () => {
|
|
49
|
+
assert.ok(output.includes("agent-agnostic"));
|
|
50
|
+
});
|
|
51
|
+
it("documents all 5 Memory Bank files", () => {
|
|
52
|
+
assert.ok(output.includes("activeContext.md"));
|
|
53
|
+
assert.ok(output.includes("systemPatterns.md"));
|
|
54
|
+
assert.ok(output.includes("techContext.md"));
|
|
55
|
+
assert.ok(output.includes("productContext.md"));
|
|
56
|
+
assert.ok(output.includes("progress.md"));
|
|
57
|
+
});
|
|
58
|
+
it("documents the Triangulation pattern", () => {
|
|
59
|
+
assert.ok(output.includes("ARCHITECT"));
|
|
60
|
+
assert.ok(output.includes("EXECUTOR"));
|
|
61
|
+
});
|
|
62
|
+
it("includes a payload example with v2.0", () => {
|
|
63
|
+
assert.ok(output.includes('<payload version="2.0">'));
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
describe("activeContextMd", () => {
|
|
67
|
+
const output = activeContextMd("TestProject");
|
|
68
|
+
it("includes the project name", () => {
|
|
69
|
+
assert.ok(output.includes("# Active Context - TestProject"));
|
|
70
|
+
});
|
|
71
|
+
it("has the required sections", () => {
|
|
72
|
+
assert.ok(output.includes("## Current Focus"));
|
|
73
|
+
assert.ok(output.includes("## Recent Changes"));
|
|
74
|
+
assert.ok(output.includes("## Open Decisions"));
|
|
75
|
+
});
|
|
76
|
+
it("includes a date in the recent changes table", () => {
|
|
77
|
+
assert.match(output, /\d{4}-\d{2}-\d{2}/);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("systemPatternsMd", () => {
|
|
81
|
+
const output = systemPatternsMd("TestProject");
|
|
82
|
+
it("includes the project name", () => {
|
|
83
|
+
assert.ok(output.includes("# System Patterns - TestProject"));
|
|
84
|
+
});
|
|
85
|
+
it("has the required sections", () => {
|
|
86
|
+
assert.ok(output.includes("## Tech Stack"));
|
|
87
|
+
assert.ok(output.includes("## Conventions"));
|
|
88
|
+
assert.ok(output.includes("## Key Decisions"));
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
describe("productContextMd", () => {
|
|
92
|
+
it("includes the project name and description", () => {
|
|
93
|
+
const output = productContextMd("TestProject", "A cool tool");
|
|
94
|
+
assert.ok(output.includes("# Product Context - TestProject"));
|
|
95
|
+
assert.ok(output.includes("A cool tool"));
|
|
96
|
+
});
|
|
97
|
+
it("shows placeholder when description is empty", () => {
|
|
98
|
+
const output = productContextMd("TestProject", "");
|
|
99
|
+
assert.ok(output.includes("_Describe your product here._"));
|
|
100
|
+
});
|
|
101
|
+
it("has the required sections", () => {
|
|
102
|
+
const output = productContextMd("TestProject", "desc");
|
|
103
|
+
assert.ok(output.includes("## Problem"));
|
|
104
|
+
assert.ok(output.includes("## Solution"));
|
|
105
|
+
assert.ok(output.includes("## Target Users"));
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
describe("techContextMd", () => {
|
|
109
|
+
const output = techContextMd("TestProject");
|
|
110
|
+
it("includes the project name", () => {
|
|
111
|
+
assert.ok(output.includes("# Tech Context - TestProject"));
|
|
112
|
+
});
|
|
113
|
+
it("has a stack table", () => {
|
|
114
|
+
assert.ok(output.includes("| Language |"));
|
|
115
|
+
assert.ok(output.includes("| Runtime |"));
|
|
116
|
+
});
|
|
117
|
+
it("includes project structure with project name", () => {
|
|
118
|
+
assert.ok(output.includes("TestProject/"));
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
describe("progressMd", () => {
|
|
122
|
+
const output = progressMd("TestProject");
|
|
123
|
+
it("includes the project name", () => {
|
|
124
|
+
assert.ok(output.includes("# Progress Log - TestProject"));
|
|
125
|
+
});
|
|
126
|
+
it("has an initialization milestone marked complete", () => {
|
|
127
|
+
assert.ok(output.includes("**Status**: Complete"));
|
|
128
|
+
});
|
|
129
|
+
it("has a Next Up section", () => {
|
|
130
|
+
assert.ok(output.includes("## Next Up"));
|
|
131
|
+
});
|
|
132
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pedrocivita/tocket",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "The Context Engineering Framework for Multi-Agent Workspaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"build": "tsc",
|
|
15
15
|
"start": "node dist/index.js",
|
|
16
16
|
"prepublishOnly": "npm run build",
|
|
17
|
-
"test": "
|
|
17
|
+
"test": "npm run build && node --test dist/tests/*.test.js"
|
|
18
18
|
},
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|