create-agent-room 1.2.1

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.
Files changed (58) hide show
  1. package/README.md +229 -0
  2. package/bin/cli.js +186 -0
  3. package/examples/python-project/.agent-room.json +14 -0
  4. package/examples/python-project/AGENTS.md +32 -0
  5. package/examples/rust-project/.agent-room.json +12 -0
  6. package/examples/rust-project/AGENTS.md +32 -0
  7. package/lib/color.js +31 -0
  8. package/lib/fsutil.js +218 -0
  9. package/lib/init.js +660 -0
  10. package/lib/lint-sessions.js +278 -0
  11. package/lib/metrics.js +190 -0
  12. package/lib/pr.js +176 -0
  13. package/lib/prompt.js +20 -0
  14. package/lib/session-utils.js +213 -0
  15. package/lib/sync.js +138 -0
  16. package/lib/validate.js +179 -0
  17. package/package.json +48 -0
  18. package/templates/.agent-room/anti-patterns.md +22 -0
  19. package/templates/.agent-room/coordination/handoff-protocol.md +60 -0
  20. package/templates/.agent-room/coordination/scope-boundaries.md +57 -0
  21. package/templates/.agent-room/coordination/session-log-format.md +62 -0
  22. package/templates/.agent-room/decisions.md +17 -0
  23. package/templates/.agent-room/guardrails.json +23 -0
  24. package/templates/.agent-room/guardrails.md +56 -0
  25. package/templates/.agent-room/principles.md +306 -0
  26. package/templates/.agent-room/sessions/.gitkeep +4 -0
  27. package/templates/.agent-room/skills/brainstorming.md +64 -0
  28. package/templates/.agent-room/skills/closing-the-loop.md +67 -0
  29. package/templates/.agent-room/skills/systematic-debugging.md +85 -0
  30. package/templates/.agent-room/skills/test-driven-development.md +100 -0
  31. package/templates/.agent-room/skills/verification-before-completion.md +56 -0
  32. package/templates/.agent-room/skills/writing-plans.md +87 -0
  33. package/templates/.agent-room/workflow-classifier.md +127 -0
  34. package/templates/AGENTS.md.tmpl +85 -0
  35. package/templates/adapters/CLAUDE.md.tmpl +38 -0
  36. package/templates/adapters/claude-hooks/close-the-loop-check.js +96 -0
  37. package/templates/adapters/clinerules.tmpl +14 -0
  38. package/templates/adapters/codexrules.tmpl +45 -0
  39. package/templates/adapters/cursorrules.tmpl +14 -0
  40. package/templates/adapters/git-hooks/guardrails-check.js +140 -0
  41. package/templates/adapters/git-hooks/pre-commit.tmpl +43 -0
  42. package/templates/adapters/windsurfrules.tmpl +14 -0
  43. package/templates/docs/plans/.gitkeep +0 -0
  44. package/templates/skill-packs/api-design/api-design.md +152 -0
  45. package/templates/skill-packs/code-review/code-review.md +113 -0
  46. package/templates/skill-packs/database/database-migrations.md +123 -0
  47. package/templates/skill-packs/documentation/documentation.md +155 -0
  48. package/templates/skill-packs/observability/observability.md +128 -0
  49. package/templates/skill-packs/performance/performance-optimization.md +150 -0
  50. package/templates/skill-packs/release/release-management.md +145 -0
  51. package/templates/skill-packs/security/security-principles.md +127 -0
  52. package/templates/skill-packs/testing/integration-testing.md +127 -0
  53. package/templates/stacks/python/.agent-room/skills/python-testing.md +59 -0
  54. package/templates/stacks/python/AGENTS.md.tmpl +35 -0
  55. package/templates/stacks/react/.agent-room/skills/react-component-testing.md +76 -0
  56. package/templates/stacks/react/AGENTS.md.tmpl +37 -0
  57. package/templates/stacks/typescript/.agent-room/skills/typescript-testing.md +63 -0
  58. package/templates/stacks/typescript/AGENTS.md.tmpl +36 -0
@@ -0,0 +1,213 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Session state utilities for agents
5
+ * Provides helpers to create, read, and manage session logs
6
+ *
7
+ * Usage:
8
+ * const session = require('./.agent-room/utils/session-utils');
9
+ * const log = session.createLog({
10
+ * goal: 'Add user API',
11
+ * classification: 'Feature'
12
+ * });
13
+ * log.addAction('Designed database schema');
14
+ * log.addFile('created', 'schema.sql');
15
+ * log.save();
16
+ */
17
+
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+
21
+ const SESSION_DIR = path.join(process.cwd(), '.agent-room', 'sessions');
22
+
23
+ function ensureSessionDir() {
24
+ if (!fs.existsSync(SESSION_DIR)) {
25
+ fs.mkdirSync(SESSION_DIR, { recursive: true });
26
+ }
27
+ }
28
+
29
+ function generateTimestamp() {
30
+ const now = new Date();
31
+ const year = now.getFullYear();
32
+ const month = String(now.getMonth() + 1).padStart(2, '0');
33
+ const day = String(now.getDate()).padStart(2, '0');
34
+ const hours = String(now.getHours()).padStart(2, '0');
35
+ const minutes = String(now.getMinutes()).padStart(2, '0');
36
+ return `${year}-${month}-${day}-${hours}-${minutes}`;
37
+ }
38
+
39
+ class SessionLog {
40
+ constructor(options = {}) {
41
+ this.timestamp = generateTimestamp();
42
+ this.date = new Date().toISOString().slice(0, 16).replace('T', ' ');
43
+ this.agent = options.agent || 'Unknown Agent';
44
+ this.classification = options.classification || 'Enhancement';
45
+ this.goal = options.goal || '';
46
+ this.actions = [];
47
+ this.files = { read: [], created: [], modified: [] };
48
+ this.tests = { command: '', result: '' };
49
+ this.decisions = [];
50
+ this.outcome = 'In Progress';
51
+ this.handoffNote = '';
52
+ this.topic = options.topic || 'session';
53
+ }
54
+
55
+ addAction(description) {
56
+ this.actions.push(description);
57
+ return this;
58
+ }
59
+
60
+ addFile(type, filePath) {
61
+ if (['read', 'created', 'modified'].includes(type)) {
62
+ this.files[type].push(filePath);
63
+ }
64
+ return this;
65
+ }
66
+
67
+ addDecision(decision) {
68
+ this.decisions.push(decision);
69
+ return this;
70
+ }
71
+
72
+ setTests(command, result) {
73
+ this.tests.command = command;
74
+ this.tests.result = result;
75
+ return this;
76
+ }
77
+
78
+ complete(handoffNote = '') {
79
+ this.outcome = 'Completed';
80
+ this.handoffNote = handoffNote;
81
+ return this;
82
+ }
83
+
84
+ handOff(handoffNote = '') {
85
+ this.outcome = 'Handed Off';
86
+ this.handoffNote = handoffNote;
87
+ return this;
88
+ }
89
+
90
+ toMarkdown() {
91
+ const files = [];
92
+ if (this.files.read.length > 0) {
93
+ files.push(`- Read: ${this.files.read.join(', ')}`);
94
+ }
95
+ if (this.files.created.length > 0) {
96
+ files.push(`- Created: ${this.files.created.join(', ')}`);
97
+ }
98
+ if (this.files.modified.length > 0) {
99
+ files.push(`- Modified: ${this.files.modified.join(', ')}`);
100
+ }
101
+
102
+ const actions = this.actions.map((a, i) => `${i + 1}. ${a}`).join('\n');
103
+
104
+ const decisions = this.decisions.length > 0 ? this.decisions.map((d) => `- ${d}`).join('\n') : 'None documented.';
105
+
106
+ const handoff = this.handoffNote ? `\n**Handoff note (if applicable):**\n${this.handoffNote}` : '';
107
+
108
+ return `# Session Log: ${this.topic}
109
+
110
+ **Date:** ${this.date}
111
+ **Agent:** ${this.agent}
112
+ **Classification:** ${this.classification}
113
+
114
+ ## Goal
115
+ ${this.goal}
116
+
117
+ ## Files touched
118
+ ${files.length > 0 ? files.join('\n') : 'None'}
119
+
120
+ ## Actions taken
121
+ ${actions}
122
+
123
+ ## Tests run
124
+ Command: ${this.tests.command}
125
+ Result: ${this.tests.result}
126
+
127
+ ## Decisions made
128
+ ${decisions}
129
+
130
+ ## Outcome
131
+ **Status:** ${this.outcome}${handoff}
132
+ `;
133
+ }
134
+
135
+ toJSON() {
136
+ return {
137
+ timestamp: this.timestamp,
138
+ date: this.date,
139
+ agent: this.agent,
140
+ classification: this.classification,
141
+ goal: this.goal,
142
+ actions: this.actions,
143
+ files: this.files,
144
+ tests: this.tests,
145
+ decisions: this.decisions,
146
+ outcome: this.outcome,
147
+ handoffNote: this.handoffNote
148
+ };
149
+ }
150
+
151
+ save(format = 'markdown') {
152
+ ensureSessionDir();
153
+
154
+ const fileName = `${this.timestamp}-${this.topic.replace(/\s+/g, '-').toLowerCase()}`;
155
+ const ext = format === 'json' ? '.json' : '.md';
156
+ const filePath = path.join(SESSION_DIR, fileName + ext);
157
+
158
+ let content;
159
+ if (format === 'json') {
160
+ content = JSON.stringify(this.toJSON(), null, 2);
161
+ } else {
162
+ content = this.toMarkdown();
163
+ }
164
+
165
+ fs.writeFileSync(filePath, content, 'utf8');
166
+ return { path: filePath, relativePath: path.relative(process.cwd(), filePath) };
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Create a new session log
172
+ * @param {Object} options - Configuration
173
+ * @param {string} options.goal - The session goal
174
+ * @param {string} options.agent - Agent name (default: "Unknown Agent")
175
+ * @param {string} options.classification - Bug, Enhancement, Feature, or Product (default: "Enhancement")
176
+ * @param {string} options.topic - Topic for filename (default: "session")
177
+ * @returns {SessionLog}
178
+ */
179
+ function createLog(options = {}) {
180
+ return new SessionLog(options);
181
+ }
182
+
183
+ /**
184
+ * List all session logs
185
+ * @returns {Array} List of session log paths
186
+ */
187
+ function listSessions() {
188
+ ensureSessionDir();
189
+ if (!fs.existsSync(SESSION_DIR)) {
190
+ return [];
191
+ }
192
+ return fs.readdirSync(SESSION_DIR)
193
+ .filter((f) => f.endsWith('.md') || f.endsWith('.json'))
194
+ .map((f) => path.join(SESSION_DIR, f));
195
+ }
196
+
197
+ /**
198
+ * Get the latest session log
199
+ * @returns {string|null} Path to latest session log or null if none exist
200
+ */
201
+ function getLatestSession() {
202
+ const sessions = listSessions();
203
+ if (sessions.length === 0) return null;
204
+ return sessions.sort().reverse()[0];
205
+ }
206
+
207
+ module.exports = {
208
+ createLog,
209
+ SessionLog,
210
+ listSessions,
211
+ getLatestSession,
212
+ generateTimestamp
213
+ };
package/lib/sync.js ADDED
@@ -0,0 +1,138 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { execSync } = require('child_process');
6
+
7
+ function isGitDirty(target, relativePath) {
8
+ try {
9
+ const res = execSync(`git status --porcelain "${relativePath}"`, {
10
+ cwd: target,
11
+ stdio: ['ignore', 'pipe', 'ignore']
12
+ }).toString();
13
+ return res.trim().length > 0;
14
+ } catch (err) {
15
+ return false;
16
+ }
17
+ }
18
+
19
+ function checkSkillsSync(target) {
20
+ const srcDir = path.join(target, '.agent-room', 'skills');
21
+ const outOfSync = [];
22
+ if (!fs.existsSync(srcDir)) {
23
+ return outOfSync;
24
+ }
25
+
26
+ for (const file of fs.readdirSync(srcDir)) {
27
+ if (!file.endsWith('.md')) continue;
28
+ const skillName = file.replace(/\.md$/, '');
29
+ const dest = path.join(target, '.claude', 'skills', skillName, 'SKILL.md');
30
+ const relativeDest = path.relative(target, dest);
31
+
32
+ if (!fs.existsSync(dest)) {
33
+ outOfSync.push({ path: relativeDest, reason: 'missing' });
34
+ continue;
35
+ }
36
+
37
+ const srcContent = fs.readFileSync(path.join(srcDir, file), 'utf8');
38
+ const destContent = fs.readFileSync(dest, 'utf8');
39
+ if (srcContent !== destContent) {
40
+ outOfSync.push({ path: relativeDest, reason: 'different' });
41
+ }
42
+ }
43
+ return outOfSync;
44
+ }
45
+
46
+ function syncSkillsToClaude(target) {
47
+ const srcDir = path.join(target, '.agent-room', 'skills');
48
+ const results = [];
49
+ for (const file of fs.readdirSync(srcDir)) {
50
+ if (!file.endsWith('.md')) continue;
51
+ const skillName = file.replace(/\.md$/, '');
52
+ const dest = path.join(target, '.claude', 'skills', skillName, 'SKILL.md');
53
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
54
+ fs.writeFileSync(dest, fs.readFileSync(path.join(srcDir, file), 'utf8'));
55
+ results.push({ path: path.relative(target, dest) });
56
+ }
57
+ return results;
58
+ }
59
+
60
+ function runSync(target, args) {
61
+ const checkOnly = !!(args && args.check);
62
+ const force = !!(args && args.force);
63
+
64
+ const configPath = path.join(target, '.agent-room.json');
65
+ let tools = [];
66
+ if (fs.existsSync(configPath)) {
67
+ try {
68
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
69
+ if (config && Array.isArray(config.tools)) {
70
+ tools = config.tools;
71
+ }
72
+ } catch (err) {
73
+ console.warn(`Warning: Failed to parse .agent-room.json: ${err.message}`);
74
+ }
75
+ }
76
+
77
+ const agentRoomDir = path.join(target, '.agent-room', 'skills');
78
+ if (!fs.existsSync(agentRoomDir)) {
79
+ throw new Error(`No .agent-room/skills/ found in ${target} - run "create-agent-room init" first.`);
80
+ }
81
+
82
+ if (tools.length === 0) {
83
+ if (fs.existsSync(path.join(target, 'CLAUDE.md')) || fs.existsSync(path.join(target, '.claude'))) {
84
+ tools.push('claude');
85
+ }
86
+ }
87
+
88
+ if (!tools.includes('claude')) {
89
+ console.log('No tools requiring sync found in project configuration - nothing to sync.');
90
+ return;
91
+ }
92
+
93
+ if (checkOnly) {
94
+ console.log('Checking if mirrored skills are out of sync...');
95
+ const outOfSync = checkSkillsSync(target);
96
+ if (outOfSync.length > 0) {
97
+ for (const item of outOfSync) {
98
+ console.log(` out-of-sync ${item.path} (${item.reason})`);
99
+ }
100
+ console.error('\nError: Mirrored skills are out of sync. Run "create-agent-room sync" to update them.');
101
+ process.exitCode = 1;
102
+ } else {
103
+ console.log('All mirrored skills are up to date.');
104
+ }
105
+ return;
106
+ }
107
+
108
+ const srcDir = path.join(target, '.agent-room', 'skills');
109
+ const results = [];
110
+ for (const file of fs.readdirSync(srcDir)) {
111
+ if (!file.endsWith('.md')) continue;
112
+ const skillName = file.replace(/\.md$/, '');
113
+ const dest = path.join(target, '.claude', 'skills', skillName, 'SKILL.md');
114
+ const relativeDest = path.relative(target, dest);
115
+
116
+ if (fs.existsSync(dest) && !force) {
117
+ if (isGitDirty(target, relativeDest)) {
118
+ console.log(` skipped ${relativeDest} (has unsaved modifications, use --force to overwrite)`);
119
+ results.push({ path: relativeDest, written: false, reason: 'dirty' });
120
+ continue;
121
+ }
122
+ }
123
+
124
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
125
+ fs.writeFileSync(dest, fs.readFileSync(path.join(srcDir, file), 'utf8'));
126
+ console.log(` synced ${relativeDest}`);
127
+ results.push({ path: relativeDest, written: true });
128
+ }
129
+
130
+ const skipped = results.filter((r) => !r.written && r.reason === 'dirty');
131
+ if (skipped.length > 0) {
132
+ console.warn(`\nWarning: ${skipped.length} mirrored file(s) had unsaved modifications and were skipped to prevent overwriting your edits. Use --force to discard modifications.`);
133
+ } else {
134
+ console.log('\nSynced .agent-room/skills/* into .claude/skills/* (source of truth is .agent-room/skills/).');
135
+ }
136
+ }
137
+
138
+ module.exports = { runSync, syncSkillsToClaude, checkSkillsSync, isGitDirty };
@@ -0,0 +1,179 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { green, yellow, red, cyan, bold } = require('./color');
6
+
7
+ function runValidate(target) {
8
+ console.log(bold(`Running agent-room integrity checks in: ${cyan(target)}\n`));
9
+
10
+ let failed = false;
11
+ const errors = [];
12
+ const warnings = [];
13
+
14
+ const checkFile = (relPath, required = true) => {
15
+ const fullPath = path.join(target, relPath);
16
+ if (!fs.existsSync(fullPath)) {
17
+ if (required) {
18
+ errors.push(`Missing required file: ${relPath}`);
19
+ failed = true;
20
+ } else {
21
+ warnings.push(`Recommended file not found: ${relPath}`);
22
+ }
23
+ return false;
24
+ }
25
+ return true;
26
+ };
27
+
28
+ const checkDir = (relPath, required = true) => {
29
+ const fullPath = path.join(target, relPath);
30
+ if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isDirectory()) {
31
+ if (required) {
32
+ errors.push(`Missing required directory: ${relPath}`);
33
+ failed = true;
34
+ } else {
35
+ warnings.push(`Recommended directory not found: ${relPath}`);
36
+ }
37
+ return false;
38
+ }
39
+ return true;
40
+ };
41
+
42
+ // 1. Check Directory and Files Structure
43
+ checkFile('AGENTS.md');
44
+ checkFile('.agent-room.json');
45
+ checkDir('.agent-room');
46
+
47
+ if (fs.existsSync(path.join(target, '.agent-room'))) {
48
+ checkFile('.agent-room/principles.md');
49
+ checkFile('.agent-room/workflow-classifier.md');
50
+ checkFile('.agent-room/guardrails.md');
51
+ checkFile('.agent-room/guardrails.json');
52
+ checkFile('.agent-room/anti-patterns.md');
53
+ checkFile('.agent-room/decisions.md');
54
+
55
+ // Check coordination structure
56
+ if (checkDir('.agent-room/coordination')) {
57
+ checkFile('.agent-room/coordination/handoff-protocol.md');
58
+ checkFile('.agent-room/coordination/scope-boundaries.md');
59
+ checkFile('.agent-room/coordination/session-log-format.md');
60
+ }
61
+
62
+ checkDir('.agent-room/sessions');
63
+
64
+ // 2. Validate guardrails.json Configuration
65
+ const guardrailsPath = path.join(target, '.agent-room/guardrails.json');
66
+ if (fs.existsSync(guardrailsPath)) {
67
+ try {
68
+ const content = fs.readFileSync(guardrailsPath, 'utf8');
69
+ const data = JSON.parse(content);
70
+
71
+ const requiredArrays = ['protectedPaths', 'requireApprovalFor', 'forbiddenActions'];
72
+ for (const prop of requiredArrays) {
73
+ if (!data[prop]) {
74
+ errors.push(`guardrails.json is missing required property: ${prop}`);
75
+ failed = true;
76
+ } else if (!Array.isArray(data[prop])) {
77
+ errors.push(`guardrails.json property "${prop}" must be an array`);
78
+ failed = true;
79
+ }
80
+ }
81
+ } catch (err) {
82
+ errors.push(`Failed to parse guardrails.json: ${err.message}`);
83
+ failed = true;
84
+ }
85
+ }
86
+
87
+ // 3. Lint Markdown Skill Files
88
+ const skillsDir = path.join(target, '.agent-room/skills');
89
+ if (fs.existsSync(skillsDir) && fs.statSync(skillsDir).isDirectory()) {
90
+ const files = fs.readdirSync(skillsDir).filter((f) => f.endsWith('.md'));
91
+ if (files.length === 0) {
92
+ warnings.push('No skill files found under .agent-room/skills/');
93
+ }
94
+
95
+ for (const file of files) {
96
+ const filePath = path.join(skillsDir, file);
97
+ try {
98
+ const content = fs.readFileSync(filePath, 'utf8');
99
+
100
+ // Parse YAML Frontmatter
101
+ const fmRegex = /^---\r?\n([\s\S]*?)\r?\n---/;
102
+ const match = content.match(fmRegex);
103
+
104
+ if (!match) {
105
+ errors.push(`Skill file "${path.join('.agent-room/skills', file)}" is missing valid YAML frontmatter delimiters (---)`);
106
+ failed = true;
107
+ continue;
108
+ }
109
+
110
+ const fmContent = match[1];
111
+ const lines = fmContent.split(/\r?\n/);
112
+ const metadata = {};
113
+
114
+ for (const line of lines) {
115
+ const separatorIndex = line.indexOf(':');
116
+ if (separatorIndex !== -1) {
117
+ const key = line.slice(0, separatorIndex).trim();
118
+ const val = line.slice(separatorIndex + 1).trim();
119
+ metadata[key] = val;
120
+ }
121
+ }
122
+
123
+ if (!metadata.name) {
124
+ errors.push(`Skill file "${path.join('.agent-room/skills', file)}" is missing the "name" metadata attribute in its frontmatter`);
125
+ failed = true;
126
+ } else {
127
+ const cleanName = metadata.name.replace(/['"]/g, '').trim();
128
+ if (!cleanName) {
129
+ errors.push(`Skill file "${path.join('.agent-room/skills', file)}" has an empty "name" attribute`);
130
+ failed = true;
131
+ }
132
+ }
133
+
134
+ if (!metadata.description) {
135
+ errors.push(`Skill file "${path.join('.agent-room/skills', file)}" is missing the "description" metadata attribute in its frontmatter`);
136
+ failed = true;
137
+ } else {
138
+ const cleanDesc = metadata.description.replace(/['"]/g, '').trim();
139
+ if (!cleanDesc) {
140
+ errors.push(`Skill file "${path.join('.agent-room/skills', file)}" has an empty "description" attribute`);
141
+ failed = true;
142
+ }
143
+ }
144
+ } catch (err) {
145
+ errors.push(`Failed to read or parse skill file ${file}: ${err.message}`);
146
+ failed = true;
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ // Output Results
153
+ if (warnings.length > 0) {
154
+ console.log(bold(yellow('Warnings:')));
155
+ for (const w of warnings) {
156
+ console.log(yellow(` ⚠️ ${w}`));
157
+ }
158
+ console.log('');
159
+ }
160
+
161
+ if (failed) {
162
+ console.log(bold(red('Validation FAILED:')));
163
+ for (const e of errors) {
164
+ console.log(red(` ❌ ${e}`));
165
+ }
166
+ console.log('');
167
+ process.exitCode = 1;
168
+ } else {
169
+ console.log(bold(green('Validation PASSED!')));
170
+ console.log(green(' ✅ All core files are present.'));
171
+ console.log(green(' ✅ guardrails.json is valid and populated.'));
172
+ console.log(green(' ✅ All skills have valid frontmatter metadata.'));
173
+ console.log('');
174
+ }
175
+ }
176
+
177
+ module.exports = {
178
+ runValidate
179
+ };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "create-agent-room",
3
+ "version": "1.2.1",
4
+ "description": "Scaffold an LLM-agent-friendly project structure: AGENTS.md, principles, workflow classifier, anti-patterns/decisions logs, and core skills (brainstorming, writing-plans, TDD, systematic debugging, verification-before-completion).",
5
+ "bin": {
6
+ "create-agent-room": "bin/cli.js"
7
+ },
8
+ "main": "lib/init.js",
9
+ "files": [
10
+ "bin",
11
+ "lib",
12
+ "templates",
13
+ "examples",
14
+ "README.md"
15
+ ],
16
+ "engines": {
17
+ "node": ">=18"
18
+ },
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/sipandey/create-agent-room.git"
23
+ },
24
+ "homepage": "https://github.com/sipandey/create-agent-room#readme",
25
+ "bugs": {
26
+ "url": "https://github.com/sipandey/create-agent-room/issues"
27
+ },
28
+ "keywords": [
29
+ "llm",
30
+ "agents",
31
+ "ai-agents",
32
+ "claude",
33
+ "cursor",
34
+ "windsurf",
35
+ "scaffold",
36
+ "cli",
37
+ "agents-md",
38
+ "governance"
39
+ ],
40
+ "author": "Siddharth Pandey",
41
+ "scripts": {
42
+ "test": "node --test test/**/*.test.js",
43
+ "lint": "eslint ."
44
+ },
45
+ "devDependencies": {
46
+ "eslint": "^8.57.0"
47
+ }
48
+ }
@@ -0,0 +1,22 @@
1
+ # Anti-Patterns Log — {{PROJECT_NAME}}
2
+
3
+ Negative knowledge: things that have already gone wrong here, so nobody
4
+ (human or agent) repeats them. One avoided bug is worth more than one
5
+ polished example — keep entries short and concrete.
6
+
7
+ Append a new entry every time:
8
+ - a bug slips through and you find the root cause,
9
+ - an approach seemed reasonable but turned out wrong,
10
+ - a fix gets reverted because it only patched a symptom.
11
+
12
+ ## Format
13
+
14
+ ```
15
+ ### YYYY-MM-DD — short title
16
+
17
+ **What happened:** one or two sentences.
18
+ **Root cause:** the actual cause, not the symptom.
19
+ **Avoid:** the concrete rule that would have prevented it.
20
+ ```
21
+
22
+ <!-- Entries go below this line, newest first. -->
@@ -0,0 +1,60 @@
1
+ # Agent Handoff Protocol
2
+
3
+ ## Overview
4
+
5
+ Modern agent workflows often involve multiple sessions, orchestrators,
6
+ and sub-agents. A handoff protocol ensures that context isn't lost when
7
+ one agent finishes its turn and another begins. The receiving agent
8
+ must not have to guess what was already done or what assumptions were
9
+ made.
10
+
11
+ ## The iron law
12
+
13
+ ```
14
+ NEVER END A SESSION WITH "WIP" — ALWAYS SERIALIZE STATE
15
+ ```
16
+
17
+ If an agent session is ending before the full feature is complete, it
18
+ must serialize its state so the next session can pick up exactly where
19
+ it left off.
20
+
21
+ ## The Handoff Note
22
+
23
+ When handing off work, write a handoff note (either in the chat, in a
24
+ PR description, or in the session log). It must include:
25
+
26
+ 1. **Completed:** What is definitively finished and verified.
27
+ 2. **In Progress:** What is partially built but not yet working.
28
+ 3. **Blocked On:** What is preventing completion (missing credentials,
29
+ unclear requirements, failing dependency).
30
+ 4. **Assumptions:** Any decisions made during the session that the next
31
+ agent needs to know.
32
+
33
+ ### Example Handoff Note
34
+
35
+ ```markdown
36
+ **Completed:**
37
+ - User model and database migration.
38
+ - `POST /register` route (handler skeleton exists, validation not started).
39
+
40
+ **In Progress:**
41
+ - Email verification service.
42
+
43
+ **Blocked On:**
44
+ - Need SMTP credentials in the `.env` file to test the email service.
45
+
46
+ **Assumptions:**
47
+ - Using `bcrypt` for passwords per decision in `.agent-room/decisions.md`.
48
+ ```
49
+
50
+ ## Receiving Handoffs
51
+
52
+ When you are the receiving agent (starting a new session):
53
+
54
+ 1. **Re-verify, don't trust:** Do not blindly trust the previous agent's
55
+ "Completed" list. Run the tests. Check the diff. Verify the state
56
+ yourself.
57
+ 2. **Read decisions:** Check `.agent-room/decisions.md` to understand
58
+ *why* the previous agent made the choices it did.
59
+ 3. **Address blockers first:** If the handoff note lists blockers,
60
+ resolve them (or escalate them to the user) before writing new code.