@automagik/genie 4.260402.6 → 4.260402.8
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/.claude-plugin/marketplace.json +1 -1
- package/dist/genie.js +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/genie/.claude-plugin/plugin.json +1 -1
- package/plugins/genie/package.json +1 -1
- package/skills/brain/SKILL.md +98 -157
- package/src/term-commands/brain.ts +20 -5
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"plugins": [
|
|
11
11
|
{
|
|
12
12
|
"name": "genie",
|
|
13
|
-
"version": "4.260402.
|
|
13
|
+
"version": "4.260402.8",
|
|
14
14
|
"source": "./plugins/genie",
|
|
15
15
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, wish them into plans, make with parallel agents, ship as one team. A coding genie that grows with your project."
|
|
16
16
|
}
|
package/dist/genie.js
CHANGED
|
@@ -2292,7 +2292,7 @@ Board: ${board.name} (${board.id})`),board.description)console.log(`Description:
|
|
|
2292
2292
|
Columns:`);for(let i2=0;i2<sorted.length;i2++){let c=sorted[i2],count=countByColumn.get(c.name)??countByColumn.get(c.id)??0,gate=` [gate: ${c.gate}]`,action=c.action?` (action: ${c.action})`:"";console.log(` ${i2+1}. ${c.label??c.name}${gate}${action} \u2014 ${count} task${count===1?"":"s"}`)}console.log("")}function buildColumnUpdates(options){let updates={};if(options.gate)updates.gate=options.gate;if(options.action)updates.action=options.action;if(options.color)updates.color=options.color;if(options.rename)updates.name=options.rename,updates.label=options.rename;return updates}async function handleBoardEdit(name,options){let bs=await getBoardService(),board=await resolveBoard(name,options.project);if(options.column){let col=board.columns.find((c)=>c.name===options.column||c.label===options.column);if(!col)throw Error(`Column not found: ${options.column}`);let updates=buildColumnUpdates(options);if(!await bs.updateColumn(board.id,col.id,updates))throw Error(`Failed to update column: ${options.column}`);console.log(`Updated column "${options.column}" on board "${board.name}".`);return}let boardUpdates={};if(options.name)boardUpdates.name=options.name;if(options.description)boardUpdates.description=options.description;if(Object.keys(boardUpdates).length===0)console.error("Error: No updates specified. Use --column, --name, or --description."),process.exit(1);let updated=await bs.updateBoard(board.id,boardUpdates);if(!updated)throw Error(`Failed to update board: ${name}`);console.log(`Updated board "${updated.name}" (${updated.id}).`)}async function handleBoardDelete(name,options){let bs=await getBoardService(),board=await resolveBoard(name,options.project);if(!options.force)console.log(`Deleting board "${board.name}" (${board.id})...`);if(!await bs.deleteBoard(board.id))throw Error(`Failed to delete board: ${name}`);console.log(`Deleted board "${board.name}" (${board.id}).`)}async function handleBoardColumns(name,options){let board=await resolveBoard(name,options.project);if(options.json){console.log(JSON.stringify(board.columns,null,2));return}printColumnPipeline(board.columns,`Board: ${board.name} (${board.columns.length} columns)`)}async function handleBoardUse(name,options){let board=await resolveBoard(name,options.project),repoRoot=execSync8("git rev-parse --show-toplevel",{encoding:"utf-8"}).trim(),genieDir=join36(repoRoot,".genie"),configPath2=join36(genieDir,"config.json");if(!existsSync27(genieDir))mkdirSync12(genieDir,{recursive:!0});let config={};if(existsSync27(configPath2))try{config=JSON.parse(readFileSync14(configPath2,"utf-8"))}catch{}config.activeBoard=board.id,writeFileSync11(configPath2,`${JSON.stringify(config,null,2)}
|
|
2293
2293
|
`),console.log(`Active board set to "${board.name}" (${board.id})`)}async function handleBoardExport(name,options){let bs=await getBoardService(),board=await resolveBoard(name,options.project),exported=await bs.exportBoard(board.id),json2=JSON.stringify(exported,null,2);if(options.output){let dir=dirname6(options.output);if(!existsSync27(dir))mkdirSync12(dir,{recursive:!0});writeFileSync11(options.output,`${json2}
|
|
2294
2294
|
`),console.log(`Exported board "${board.name}" to ${options.output}`)}else console.log(json2)}async function handleBoardReconcile(name,options){let{reconcileBoard:reconcileBoard2}=await Promise.resolve().then(() => (init_board_service(),exports_board_service)),board=await resolveBoard(name,options.project),result=await reconcileBoard2(board.id);if(options.json){console.log(JSON.stringify(result,null,2));return}if(result.fixed===0&&result.orphaned===0){console.log(`Board "${board.name}": all tasks have valid column_ids.`);return}if(console.log(`Board "${board.name}" reconciliation:`),console.log(` Fixed: ${result.fixed} task${result.fixed===1?"":"s"}`),result.orphaned>0){let count=result.orphaned;console.log(` Still orphaned: ${count} task${count===1?"":"s"} (stage doesn't match any column)`)}}async function handleBoardImport(options){let bs=await getBoardService(),projectId=await resolveProjectId(options.project),raw=readFileSync14(options.json,"utf-8"),data=JSON.parse(raw),board=await bs.importBoard(data,projectId);console.log(`Imported board "${board.name}" (${board.id}) with ${board.columns.length} columns`)}async function handleTemplateList(options){let templates=await(await getTemplateService()).listTemplates();if(options.json){console.log(JSON.stringify(templates,null,2));return}printTemplateTable(templates)}async function handleTemplateShow(name,options){let template=await(await getTemplateService()).getTemplate(name);if(!template)throw Error(`Template not found: ${name}`);if(options.json){console.log(JSON.stringify(template,null,2));return}if(console.log(`
|
|
2295
|
-
Template: ${template.name} (${template.id})`),template.description)console.log(`Description: ${template.description}`);if(template.icon)console.log(`Icon: ${template.icon}`);console.log(`Built-in: ${template.isBuiltin?"yes":"no"}`),printColumnPipeline(template.columns,`Pipeline (${template.columns.length} columns)`)}async function handleTemplateCreate(name,options){let tmpl=await getTemplateService();if(options.fromBoard){let board=await(await getBoardService()).getBoard(options.fromBoard);if(!board)throw Error(`Board not found: ${options.fromBoard}`);let template2=await tmpl.snapshotFromBoard(board.id,name);console.log(`Created template "${template2.name}" (${template2.id}) from board "${board.name}" with ${template2.columns.length} columns`);return}let columns;if(options.columns)columns=options.columns.split(",").map((colName,i2)=>({id:crypto.randomUUID(),name:colName.trim(),label:colName.trim(),gate:"human",action:null,auto_advance:!1,transitions:[],roles:["*"],color:"#94a3b8",parallel:!1,on_fail:null,position:i2}));let template=await tmpl.createTemplate({name,description:options.description,columns});console.log(`Created template "${template.name}" (${template.id}) with ${template.columns.length} columns`)}async function handleTemplateEdit(name,options){let tmpl=await getTemplateService(),template=await tmpl.getTemplate(name);if(!template)throw Error(`Template not found: ${name}`);if(!options.column)console.error("Error: --column is required for template edit."),process.exit(1);let updates={};if(options.gate)updates.gate=options.gate;if(options.action)updates.action=options.action;if(options.color)updates.color=options.color;if(options.rename)updates.name=options.rename,updates.label=options.rename;if(!await tmpl.updateTemplateColumn(template.id,options.column,updates))throw Error(`Failed to update template: ${name}`);console.log(`Updated column "${options.column}" on template "${template.name}".`)}async function handleTemplateRename(oldName,newName){let tmpl=await getTemplateService(),template=await tmpl.getTemplate(oldName);if(!template)throw Error(`Template not found: ${oldName}`);let updated=await tmpl.renameTemplate(template.id,newName);if(!updated)throw Error(`Failed to rename template: ${oldName}`);console.log(`Renamed template "${oldName}" to "${updated.name}".`)}async function handleTemplateDelete(name){let tmpl=await getTemplateService(),template=await tmpl.getTemplate(name);if(!template)throw Error(`Template not found: ${name}`);if(!await tmpl.deleteTemplate(template.id))throw Error(`Failed to delete template: ${name}`);console.log(`Deleted template "${template.name}" (${template.id}).`)}function registerBoardCommands(program2){let board=program2.command("board").description("Board and pipeline management");board.command("create <name>").description("Create a new board").option("--project <project>","Project name").option("--from <template>","Create from template name").option("--columns <columns>","Comma-separated column names").option("--description <text>","Board description").action(async(name,options)=>{try{await handleBoardCreate(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("list").description("List all boards").option("--project <project>","Filter by project").option("--all","Include archived boards").option("--json","Output as JSON").action(async(options)=>{try{await handleBoardList(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("show <name...>").description("Show board detail").option("--project <project>","Disambiguate by project").option("--json","Output as JSON").action(async(nameParts,options)=>{try{await handleBoardShow(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("edit <name...>").description("Edit board or column properties").option("--project <project>","Disambiguate by project").option("--column <col>","Column name to edit").option("--gate <gate>","New gate value (human|agent|human+agent)").option("--action <action>","New action skill").option("--color <color>","New color hex").option("--rename <new>","Rename the column").option("--name <new>","Rename the board itself").option("--description <text>","Update description").action(async(nameParts,options)=>{try{await handleBoardEdit(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("delete <name...>").description("Delete a board").option("--project <project>","Disambiguate by project").option("--force","Skip confirmation").action(async(nameParts,options)=>{try{await handleBoardDelete(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("columns <name...>").description("Show board column pipeline").option("--project <project>","Disambiguate by project").option("--json","Output as JSON").action(async(nameParts,options)=>{try{await handleBoardColumns(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("use <name...>").description("Set active board for current repo").option("--project <project>","Disambiguate by project").action(async(nameParts,options)=>{try{await handleBoardUse(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("export <name...>").description("Export board as JSON").option("--project <project>","Disambiguate by project").option("--output <file>","Write to file instead of stdout").option("--json","Output as JSON (default, accepted for consistency)").action(async(nameParts,options)=>{try{await handleBoardExport(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("reconcile <name...>").description("Fix orphaned column_ids by matching task stage to board columns").option("--project <project>","Disambiguate by project").option("--json","Output as JSON").action(async(nameParts,options)=>{try{await handleBoardReconcile(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("archive <name...>").description("Archive a board and its unfinished tasks").option("--project <project>","Disambiguate by project").action(async(nameParts,options)=>{try{let ts3=await getTaskService3(),board2=await resolveBoard(nameParts.join(" "),options.project);await ts3.archiveBoard(board2.id),console.log(`Archived board "${board2.name}" and its unfinished tasks.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("import").description("Import board from JSON file").requiredOption("--json <file>","JSON file to import").requiredOption("--project <project>","Target project").action(async(options)=>{try{await handleBoardImport(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}});let template=board.command("template").description("Board template management");template.command("list").description("List all board templates").option("--json","Output as JSON").action(async(options)=>{try{await handleTemplateList(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("show <name>").description("Show template detail with pipeline view").option("--json","Output as JSON").action(async(name,options)=>{try{await handleTemplateShow(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("create <name>").description("Create a board template").option("--from-board <board>","Create from existing board").option("--columns <columns>","Comma-separated column names").option("--description <text>","Template description").action(async(name,options)=>{try{await handleTemplateCreate(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("edit <name>").description("Edit a template column").option("--column <col>","Column name to edit").option("--gate <gate>","New gate value (human|agent|human+agent)").option("--action <action>","New action skill").option("--rename <new>","Rename the column").option("--color <color>","New color hex").action(async(name,options)=>{try{await handleTemplateEdit(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("rename <old> <new>").description("Rename a template").action(async(oldName,newName)=>{try{await handleTemplateRename(oldName,newName)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("delete <name>").description("Delete a template").action(async(name)=>{try{await handleTemplateDelete(name)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}import{execSync as execSync9}from"child_process";var BRAIN_PKG="@automagik/genie-brain",BRAIN_REPO="github:automagik-dev/genie-brain";async function installBrain(){console.log(""),console.log(" Installing genie-brain from GitHub (enterprise)..."),console.log(""),console.log(" Source: https://github.com/automagik-dev/genie-brain"),console.log(" Requires: GitHub org membership (automagik-dev)"),console.log("");try{execSync9(`bun add ${BRAIN_REPO}`,{stdio:"inherit"}),console.log(""),console.log(" \u2713 Brain installed from GitHub."),console.log("");try{let brain=await import(BRAIN_PKG);if(brain.runAllMigrations)console.log(" Running brain migrations..."),await brain.runAllMigrations(),console.log(" \u2713 Brain tables created in Postgres.")}catch{console.log(" \u26A0 Auto-migration skipped. Run: genie brain migrate")}return console.log(""),console.log(" Get started:"),console.log(" genie brain init --name my-brain --path ./brain"),console.log(""),!0}catch(err){let msg=err instanceof Error?err.message:String(err);if(msg.includes("Authentication")||msg.includes("permission")||msg.includes("404"))console.error(" \u2717 Access denied. Brain is enterprise-only."),console.log(""),console.log(" You need:"),console.log(" 1. Membership in the automagik-dev GitHub org"),console.log(" 2. SSH key or GH token configured for git"),console.log(""),console.log(" Manual install:"),console.log(` bun add ${BRAIN_REPO}`),console.log("");else console.error(` \u2717 Install failed: ${msg}`),console.log(""),console.log(" Manual install:"),console.log(` bun add ${BRAIN_REPO}`),console.log("");return!1}}function uninstallBrain(){try{execSync9(`bun remove ${BRAIN_PKG}`,{stdio:"inherit"}),console.log(" \u2713 Brain uninstalled.")}catch{console.error(" Uninstall failed. Manual: bun remove @automagik/genie-brain")}}function isModuleNotFound(msg){return msg.includes("Cannot find")||msg.includes("not found")||msg.includes("MODULE_NOT_FOUND")}function printNotInstalledMessage(){console.log(""),console.log(" Brain is an enterprise knowledge graph engine."),console.log(" It is not installed."),console.log(""),console.log(" Quick install:"),console.log(""),console.log(" genie brain install"),console.log(""),console.log(" Requires GitHub org membership (automagik-dev)."),console.log("")}async function executeBrainCommand(args){try{let brain=await import(BRAIN_PKG);if(brain.execute)await brain.execute(args);else console.error("Brain module loaded but execute() not found."),console.error("Update: genie brain install")}catch(err){let msg=err instanceof Error?err.message:String(err);if(isModuleNotFound(msg))printNotInstalledMessage();else console.error(`Brain error: ${msg}`)}}function registerBrainCommands(program2){program2.command("brain").description("Knowledge graph engine (enterprise)").allowUnknownOption().allowExcessArguments().action(async(_options,cmd)=>{let args=cmd.args;if(args[0]==="install"){await installBrain();return}if(args[0]==="uninstall"){uninstallBrain();return}await executeBrainCommand(args)})}var _brief2;async function getBrief2(){if(!_brief2)_brief2=await Promise.resolve().then(() => (init_brief(),exports_brief));return _brief2}async function handleBrief2(options){let team=options.team??process.env.GENIE_TEAM;if(!team)console.error("Error: --team is required (or set GENIE_TEAM)"),process.exit(1);let agent=options.agent??process.env.GENIE_AGENT_NAME,briefService=await getBrief2(),brief=await briefService.generateBrief({team,agent,since:options.since,repoPath:process.cwd()});console.log(briefService.formatBrief(brief))}function registerBriefCommands(program2){program2.command("brief").description("Show startup brief \u2014 aggregated context since last session").option("--team <name>","Team name (default: GENIE_TEAM)").option("--agent <name>","Agent name (default: GENIE_AGENT_NAME)").option("--since <iso>","Start timestamp (default: last executor end)").action(async(options)=>{try{await handleBrief2(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}import{existsSync as existsSync28,mkdirSync as mkdirSync13,readFileSync as readFileSync15,unlinkSync as unlinkSync7,writeFileSync as writeFileSync12}from"fs";import{homedir as homedir25}from"os";import{join as join37}from"path";function genieHome3(){return process.env.GENIE_HOME??join37(homedir25(),".genie")}function pidFilePath(){return join37(genieHome3(),"scheduler.pid")}function logFilePath(){return join37(genieHome3(),"logs","scheduler.log")}function systemdDir(){return join37(homedir25(),".config","systemd","user")}function systemdUnitPath(){return join37(systemdDir(),"genie-scheduler.service")}function readPid(){let path2=pidFilePath();if(!existsSync28(path2))return null;let raw=readFileSync15(path2,"utf-8").trim(),pid=Number.parseInt(raw,10);if(Number.isNaN(pid)||pid<=0)return null;return pid}function writePid(pid){let dir=genieHome3();mkdirSync13(dir,{recursive:!0}),writeFileSync12(pidFilePath(),String(pid),"utf-8")}function removePid(){let path2=pidFilePath();if(existsSync28(path2))try{unlinkSync7(path2)}catch{}}function isProcessAlive2(pid){try{return process.kill(pid,0),!0}catch{return!1}}function generateSystemdUnit(){let genieBin=process.argv[1]??"genie";return`[Unit]
|
|
2295
|
+
Template: ${template.name} (${template.id})`),template.description)console.log(`Description: ${template.description}`);if(template.icon)console.log(`Icon: ${template.icon}`);console.log(`Built-in: ${template.isBuiltin?"yes":"no"}`),printColumnPipeline(template.columns,`Pipeline (${template.columns.length} columns)`)}async function handleTemplateCreate(name,options){let tmpl=await getTemplateService();if(options.fromBoard){let board=await(await getBoardService()).getBoard(options.fromBoard);if(!board)throw Error(`Board not found: ${options.fromBoard}`);let template2=await tmpl.snapshotFromBoard(board.id,name);console.log(`Created template "${template2.name}" (${template2.id}) from board "${board.name}" with ${template2.columns.length} columns`);return}let columns;if(options.columns)columns=options.columns.split(",").map((colName,i2)=>({id:crypto.randomUUID(),name:colName.trim(),label:colName.trim(),gate:"human",action:null,auto_advance:!1,transitions:[],roles:["*"],color:"#94a3b8",parallel:!1,on_fail:null,position:i2}));let template=await tmpl.createTemplate({name,description:options.description,columns});console.log(`Created template "${template.name}" (${template.id}) with ${template.columns.length} columns`)}async function handleTemplateEdit(name,options){let tmpl=await getTemplateService(),template=await tmpl.getTemplate(name);if(!template)throw Error(`Template not found: ${name}`);if(!options.column)console.error("Error: --column is required for template edit."),process.exit(1);let updates={};if(options.gate)updates.gate=options.gate;if(options.action)updates.action=options.action;if(options.color)updates.color=options.color;if(options.rename)updates.name=options.rename,updates.label=options.rename;if(!await tmpl.updateTemplateColumn(template.id,options.column,updates))throw Error(`Failed to update template: ${name}`);console.log(`Updated column "${options.column}" on template "${template.name}".`)}async function handleTemplateRename(oldName,newName){let tmpl=await getTemplateService(),template=await tmpl.getTemplate(oldName);if(!template)throw Error(`Template not found: ${oldName}`);let updated=await tmpl.renameTemplate(template.id,newName);if(!updated)throw Error(`Failed to rename template: ${oldName}`);console.log(`Renamed template "${oldName}" to "${updated.name}".`)}async function handleTemplateDelete(name){let tmpl=await getTemplateService(),template=await tmpl.getTemplate(name);if(!template)throw Error(`Template not found: ${name}`);if(!await tmpl.deleteTemplate(template.id))throw Error(`Failed to delete template: ${name}`);console.log(`Deleted template "${template.name}" (${template.id}).`)}function registerBoardCommands(program2){let board=program2.command("board").description("Board and pipeline management");board.command("create <name>").description("Create a new board").option("--project <project>","Project name").option("--from <template>","Create from template name").option("--columns <columns>","Comma-separated column names").option("--description <text>","Board description").action(async(name,options)=>{try{await handleBoardCreate(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("list").description("List all boards").option("--project <project>","Filter by project").option("--all","Include archived boards").option("--json","Output as JSON").action(async(options)=>{try{await handleBoardList(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("show <name...>").description("Show board detail").option("--project <project>","Disambiguate by project").option("--json","Output as JSON").action(async(nameParts,options)=>{try{await handleBoardShow(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("edit <name...>").description("Edit board or column properties").option("--project <project>","Disambiguate by project").option("--column <col>","Column name to edit").option("--gate <gate>","New gate value (human|agent|human+agent)").option("--action <action>","New action skill").option("--color <color>","New color hex").option("--rename <new>","Rename the column").option("--name <new>","Rename the board itself").option("--description <text>","Update description").action(async(nameParts,options)=>{try{await handleBoardEdit(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("delete <name...>").description("Delete a board").option("--project <project>","Disambiguate by project").option("--force","Skip confirmation").action(async(nameParts,options)=>{try{await handleBoardDelete(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("columns <name...>").description("Show board column pipeline").option("--project <project>","Disambiguate by project").option("--json","Output as JSON").action(async(nameParts,options)=>{try{await handleBoardColumns(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("use <name...>").description("Set active board for current repo").option("--project <project>","Disambiguate by project").action(async(nameParts,options)=>{try{await handleBoardUse(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("export <name...>").description("Export board as JSON").option("--project <project>","Disambiguate by project").option("--output <file>","Write to file instead of stdout").option("--json","Output as JSON (default, accepted for consistency)").action(async(nameParts,options)=>{try{await handleBoardExport(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("reconcile <name...>").description("Fix orphaned column_ids by matching task stage to board columns").option("--project <project>","Disambiguate by project").option("--json","Output as JSON").action(async(nameParts,options)=>{try{await handleBoardReconcile(nameParts.join(" "),options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("archive <name...>").description("Archive a board and its unfinished tasks").option("--project <project>","Disambiguate by project").action(async(nameParts,options)=>{try{let ts3=await getTaskService3(),board2=await resolveBoard(nameParts.join(" "),options.project);await ts3.archiveBoard(board2.id),console.log(`Archived board "${board2.name}" and its unfinished tasks.`)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),board.command("import").description("Import board from JSON file").requiredOption("--json <file>","JSON file to import").requiredOption("--project <project>","Target project").action(async(options)=>{try{await handleBoardImport(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}});let template=board.command("template").description("Board template management");template.command("list").description("List all board templates").option("--json","Output as JSON").action(async(options)=>{try{await handleTemplateList(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("show <name>").description("Show template detail with pipeline view").option("--json","Output as JSON").action(async(name,options)=>{try{await handleTemplateShow(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("create <name>").description("Create a board template").option("--from-board <board>","Create from existing board").option("--columns <columns>","Comma-separated column names").option("--description <text>","Template description").action(async(name,options)=>{try{await handleTemplateCreate(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("edit <name>").description("Edit a template column").option("--column <col>","Column name to edit").option("--gate <gate>","New gate value (human|agent|human+agent)").option("--action <action>","New action skill").option("--rename <new>","Rename the column").option("--color <color>","New color hex").action(async(name,options)=>{try{await handleTemplateEdit(name,options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("rename <old> <new>").description("Rename a template").action(async(oldName,newName)=>{try{await handleTemplateRename(oldName,newName)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}}),template.command("delete <name>").description("Delete a template").action(async(name)=>{try{await handleTemplateDelete(name)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}import{execSync as execSync9}from"child_process";var BRAIN_PKG="@automagik/genie-brain",BRAIN_REPO="github:automagik-dev/genie-brain";async function installBrain(){console.log(""),console.log(" Installing genie-brain from GitHub (enterprise)..."),console.log(""),console.log(" Source: https://github.com/automagik-dev/genie-brain"),console.log(" Requires: GitHub org membership (automagik-dev)"),console.log("");try{try{execSync9("gh auth token",{stdio:"pipe"})}catch{return console.error(" \u2717 GitHub CLI not authenticated. Run: gh auth login"),!1}let brainDir="node_modules/@automagik/genie-brain";execSync9(`rm -rf "${brainDir}"`,{stdio:"pipe"}),execSync9("mkdir -p node_modules/@automagik",{stdio:"pipe"}),execSync9(`gh repo clone automagik-dev/genie-brain "${brainDir}" -- --depth 1`,{stdio:"inherit"}),execSync9("bun install",{cwd:brainDir,stdio:"inherit"}),execSync9("bun run build",{cwd:brainDir,stdio:"inherit"}),console.log(""),console.log(" \u2713 Brain installed from GitHub."),console.log("");try{let brain=await import(BRAIN_PKG);if(brain.runAllMigrations)console.log(" Running brain migrations..."),await brain.runAllMigrations(),console.log(" \u2713 Brain tables created in Postgres.")}catch{console.log(" \u26A0 Auto-migration skipped. Run: genie brain migrate")}return console.log(""),console.log(" Get started:"),console.log(" genie brain init --name my-brain --path ./brain"),console.log(""),!0}catch(err){let msg=err instanceof Error?err.message:String(err);if(msg.includes("Authentication")||msg.includes("permission")||msg.includes("404"))console.error(" \u2717 Access denied. Brain is enterprise-only."),console.log(""),console.log(" You need:"),console.log(" 1. Membership in the automagik-dev GitHub org"),console.log(" 2. SSH key or GH token configured for git"),console.log(""),console.log(" Manual install:"),console.log(` bun add ${BRAIN_REPO}`),console.log("");else console.error(` \u2717 Install failed: ${msg}`),console.log(""),console.log(" Manual install:"),console.log(` bun add ${BRAIN_REPO}`),console.log("");return!1}}function uninstallBrain(){try{execSync9('rm -rf "node_modules/@automagik/genie-brain"',{stdio:"pipe"}),console.log(" \u2713 Brain uninstalled.")}catch{console.error(" Uninstall failed. Manual: rm -rf node_modules/@automagik/genie-brain")}}function isModuleNotFound(msg){return msg.includes("Cannot find")||msg.includes("not found")||msg.includes("MODULE_NOT_FOUND")}function printNotInstalledMessage(){console.log(""),console.log(" Brain is an enterprise knowledge graph engine."),console.log(" It is not installed."),console.log(""),console.log(" Quick install:"),console.log(""),console.log(" genie brain install"),console.log(""),console.log(" Requires GitHub org membership (automagik-dev)."),console.log("")}async function executeBrainCommand(args){try{let brain=await import(BRAIN_PKG);if(brain.execute)await brain.execute(args);else console.error("Brain module loaded but execute() not found."),console.error("Update: genie brain install")}catch(err){let msg=err instanceof Error?err.message:String(err);if(isModuleNotFound(msg))printNotInstalledMessage();else console.error(`Brain error: ${msg}`)}}function registerBrainCommands(program2){program2.command("brain").description("Knowledge graph engine (enterprise)").allowUnknownOption().allowExcessArguments().action(async(_options,cmd)=>{let args=cmd.args;if(args[0]==="install"){await installBrain();return}if(args[0]==="uninstall"){uninstallBrain();return}await executeBrainCommand(args)})}var _brief2;async function getBrief2(){if(!_brief2)_brief2=await Promise.resolve().then(() => (init_brief(),exports_brief));return _brief2}async function handleBrief2(options){let team=options.team??process.env.GENIE_TEAM;if(!team)console.error("Error: --team is required (or set GENIE_TEAM)"),process.exit(1);let agent=options.agent??process.env.GENIE_AGENT_NAME,briefService=await getBrief2(),brief=await briefService.generateBrief({team,agent,since:options.since,repoPath:process.cwd()});console.log(briefService.formatBrief(brief))}function registerBriefCommands(program2){program2.command("brief").description("Show startup brief \u2014 aggregated context since last session").option("--team <name>","Team name (default: GENIE_TEAM)").option("--agent <name>","Agent name (default: GENIE_AGENT_NAME)").option("--since <iso>","Start timestamp (default: last executor end)").action(async(options)=>{try{await handleBrief2(options)}catch(error2){console.error(`Error: ${error2 instanceof Error?error2.message:String(error2)}`),process.exit(1)}})}import{existsSync as existsSync28,mkdirSync as mkdirSync13,readFileSync as readFileSync15,unlinkSync as unlinkSync7,writeFileSync as writeFileSync12}from"fs";import{homedir as homedir25}from"os";import{join as join37}from"path";function genieHome3(){return process.env.GENIE_HOME??join37(homedir25(),".genie")}function pidFilePath(){return join37(genieHome3(),"scheduler.pid")}function logFilePath(){return join37(genieHome3(),"logs","scheduler.log")}function systemdDir(){return join37(homedir25(),".config","systemd","user")}function systemdUnitPath(){return join37(systemdDir(),"genie-scheduler.service")}function readPid(){let path2=pidFilePath();if(!existsSync28(path2))return null;let raw=readFileSync15(path2,"utf-8").trim(),pid=Number.parseInt(raw,10);if(Number.isNaN(pid)||pid<=0)return null;return pid}function writePid(pid){let dir=genieHome3();mkdirSync13(dir,{recursive:!0}),writeFileSync12(pidFilePath(),String(pid),"utf-8")}function removePid(){let path2=pidFilePath();if(existsSync28(path2))try{unlinkSync7(path2)}catch{}}function isProcessAlive2(pid){try{return process.kill(pid,0),!0}catch{return!1}}function generateSystemdUnit(){let genieBin=process.argv[1]??"genie";return`[Unit]
|
|
2296
2296
|
Description=Genie Scheduler Daemon
|
|
2297
2297
|
Documentation=https://github.com/automagik/genie
|
|
2298
2298
|
After=network.target
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genie",
|
|
3
|
-
"version": "4.260402.
|
|
3
|
+
"version": "4.260402.8",
|
|
4
4
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Namastex Labs"
|
package/skills/brain/SKILL.md
CHANGED
|
@@ -1,190 +1,131 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: brain
|
|
3
|
-
description: "
|
|
3
|
+
description: "Knowledge graph engine — search, analyze, and manage AI agent brains with confidence scoring, autoschema, and multimodal support."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# /brain —
|
|
6
|
+
# /brain — Knowledge Graph Engine
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## Brain vs Memory
|
|
11
|
-
|
|
12
|
-
These are **different tools for different purposes**:
|
|
13
|
-
|
|
14
|
-
| | **Brain** (this skill) | **Memory** (Claude native) |
|
|
15
|
-
|---|---|---|
|
|
16
|
-
| **What** | Context graph — entities, relationships, domain knowledge | Behavioral learnings — feedback, decisions, user preferences |
|
|
17
|
-
| **Tool** | `notesmd-cli` (Obsidian-style vault) | `.claude/memory/` files with YAML frontmatter |
|
|
18
|
-
| **When** | Domain intel, playbooks, company/person context, session logs | Corrections, conventions, project rules, user profile |
|
|
19
|
-
| **Updated by** | `/brain` (this skill) | `/learn` skill, auto memory system |
|
|
20
|
-
| **Format** | Markdown notes in `brain/` directory | Typed memory files (user, feedback, project, reference) |
|
|
21
|
-
|
|
22
|
-
**Rule of thumb:** If it's *knowledge about the world* → brain. If it's *how the agent should behave* → memory.
|
|
8
|
+
Search, analyze, and manage knowledge brains powered by genie-brain. Brains are Postgres-backed, Obsidian-compatible knowledge vaults with BM25 + vector search, confidence scoring, and agentic autoschema.
|
|
23
9
|
|
|
24
10
|
## When to Use
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
## Flow
|
|
31
|
-
|
|
32
|
-
### Session Start (mandatory)
|
|
11
|
+
- Search for knowledge before answering a question
|
|
12
|
+
- Check what the brain knows (and doesn't know) about a topic
|
|
13
|
+
- Analyze content with deep reasoning
|
|
14
|
+
- Ingest new content into the brain
|
|
15
|
+
- Check brain health and coverage gaps
|
|
33
16
|
|
|
34
|
-
|
|
35
|
-
2. `notesmd-cli search-content "<term>"` for each term.
|
|
36
|
-
3. `notesmd-cli print "<note-name>"` for relevant hits.
|
|
37
|
-
4. Only then begin forming a response.
|
|
38
|
-
5. Fall back to external research (web search, browser) only if brain is insufficient.
|
|
17
|
+
## Prerequisites
|
|
39
18
|
|
|
40
|
-
|
|
19
|
+
Brain must be installed: `genie brain install`
|
|
20
|
+
If not installed, guide the user to run the install command.
|
|
41
21
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
### Trigger 1: Session End (always)
|
|
22
|
+
## Commands
|
|
45
23
|
|
|
24
|
+
### Search — find knowledge with confidence
|
|
46
25
|
```bash
|
|
47
|
-
|
|
48
|
-
# Write: discussion summary, decisions, intel discovered, actions taken
|
|
26
|
+
genie brain search "<query>" --brain <id>
|
|
49
27
|
```
|
|
28
|
+
Returns ranked results with confidence level (FULL/HIGH/PARTIAL/LOW/NONE).
|
|
29
|
+
- FULL/HIGH → brain knows this well, use the results
|
|
30
|
+
- PARTIAL → brain has some info, may need to supplement
|
|
31
|
+
- LOW/NONE → gap detected, go external or research
|
|
50
32
|
|
|
51
|
-
|
|
33
|
+
**Always search before answering domain questions.** If confidence is LOW/NONE, say so — don't hallucinate.
|
|
52
34
|
|
|
35
|
+
### Health — check brain quality
|
|
53
36
|
```bash
|
|
54
|
-
|
|
55
|
-
# Write now — do not wait until session end
|
|
37
|
+
genie brain health --path <brain-path> [--fix]
|
|
56
38
|
```
|
|
39
|
+
7-dimension score: Schema, Freshness, Coverage, Connections, Content, Conflicts, Acceptance.
|
|
40
|
+
`--fix` auto-repairs: adds missing dates, converts tags, generates MOCs.
|
|
57
41
|
|
|
58
|
-
###
|
|
59
|
-
|
|
42
|
+
### Status — brain dashboard
|
|
60
43
|
```bash
|
|
61
|
-
|
|
62
|
-
# Edit: add confirmed pattern, new rule, exception, or example
|
|
44
|
+
genie brain status
|
|
63
45
|
```
|
|
46
|
+
Lists all registered brains with file counts, health, and query stats.
|
|
64
47
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
| Command | Purpose |
|
|
68
|
-
|---------|---------|
|
|
69
|
-
| `notesmd-cli search-content "<keyword>"` | Search vault content (use BEFORE answering domain questions) |
|
|
70
|
-
| `notesmd-cli print "<note-name>"` | Read a specific note |
|
|
71
|
-
| `notesmd-cli daily` | Open/create today's session log in `Daily/` |
|
|
72
|
-
| `notesmd-cli create "<name>"` | Create a note (use folder prefix: `"Intelligence/Name"`) |
|
|
73
|
-
| `notesmd-cli list` | Browse full vault structure |
|
|
74
|
-
| `notesmd-cli set-default --vault <path>` | Configure vault path (one-time setup) |
|
|
75
|
-
|
|
76
|
-
## Installation (Auto-Detect)
|
|
77
|
-
|
|
78
|
-
On first use, check if `notesmd-cli` is available:
|
|
79
|
-
|
|
48
|
+
### Init — create a new brain
|
|
80
49
|
```bash
|
|
81
|
-
|
|
50
|
+
genie brain init --name <name> --path <path> [--type gtm|pm|engineering|research|personal]
|
|
82
51
|
```
|
|
52
|
+
Creates an Obsidian-compatible vault with autoschema. Brain types provide base scaffolding.
|
|
83
53
|
|
|
84
|
-
|
|
85
|
-
|
|
54
|
+
### Process — ingest new content
|
|
86
55
|
```bash
|
|
87
|
-
|
|
88
|
-
brew install yakitrak/yakitrak/notesmd-cli
|
|
89
|
-
|
|
90
|
-
# Linux / manual
|
|
91
|
-
# Download the latest release binary from:
|
|
92
|
-
# https://github.com/Yakitrak/notesmd-cli/releases
|
|
93
|
-
# Place in /usr/local/bin/notesmd-cli and chmod +x
|
|
94
|
-
|
|
95
|
-
# Or use the bundled install script (if available)
|
|
96
|
-
bash skills/brain/scripts/install-notesmd.sh --vault ./brain
|
|
56
|
+
genie brain process --brain <id> --path <path>
|
|
97
57
|
```
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
58
|
+
Processes files in `to_process/`:
|
|
59
|
+
- Markdown → classified and moved to decided folder
|
|
60
|
+
- Images → described via Gemini Vision → .desc.md
|
|
61
|
+
- Audio → transcribed → .transcript.md
|
|
62
|
+
- PDF → extracted → .extracted.md
|
|
63
|
+
- Code → symbols extracted → .symbols.md
|
|
64
|
+
|
|
65
|
+
### Analyze — deep reasoning via rlmx
|
|
101
66
|
```bash
|
|
102
|
-
|
|
67
|
+
genie brain analyze "<query>" --brain <id> --path <path>
|
|
103
68
|
```
|
|
69
|
+
Uses rlmx reasoning engine for deep analysis with file references.
|
|
104
70
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
## Provisioning a New Agent Brain
|
|
108
|
-
|
|
71
|
+
### Link — discover connections
|
|
109
72
|
```bash
|
|
110
|
-
|
|
111
|
-
notesmd-cli set-default --vault ./brain/
|
|
112
|
-
cp skills/brain/templates/*.md brain/_Templates/
|
|
113
|
-
notesmd-cli list
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
Then add the protocol snippets below to the agent's config files.
|
|
117
|
-
|
|
118
|
-
### CLAUDE.md Template Block
|
|
119
|
-
|
|
120
|
-
```markdown
|
|
121
|
-
## FIRST THING YOU DO (every session)
|
|
122
|
-
|
|
123
|
-
1. Read the conversation opener to understand the topic
|
|
124
|
-
2. Derive 2-3 search terms
|
|
125
|
-
3. Run: `notesmd-cli search-content "<term>"` for each
|
|
126
|
-
4. If results found: `notesmd-cli print "<note-name>"`
|
|
127
|
-
5. Only THEN begin forming your response
|
|
128
|
-
6. If brain is insufficient: use web search as fallback
|
|
129
|
-
|
|
130
|
-
## WHEN TOPIC SHIFTS
|
|
131
|
-
|
|
132
|
-
Re-run `notesmd-cli search-content "<new-topic>"` before answering.
|
|
133
|
-
|
|
134
|
-
## AT SESSION END (mandatory)
|
|
135
|
-
|
|
136
|
-
Run `notesmd-cli daily`. Log: discussion, decisions, intel, actions.
|
|
137
|
-
|
|
138
|
-
## WRITE IMMEDIATELY WHEN
|
|
139
|
-
|
|
140
|
-
- New intel discovered -> `notesmd-cli create "Intelligence/<name>"`
|
|
141
|
-
- Playbook updated -> edit relevant `Playbooks/` note
|
|
142
|
-
- Domain insight validated -> update relevant `Domains/` note
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### AGENTS.md Protocol Snippet
|
|
146
|
-
|
|
147
|
-
```markdown
|
|
148
|
-
## Brain Protocol
|
|
149
|
-
|
|
150
|
-
### Session Start
|
|
151
|
-
- Derive 2-3 keywords from topic
|
|
152
|
-
- `notesmd-cli search-content "<keyword>"` for each
|
|
153
|
-
- `notesmd-cli print "<note-name>"` for relevant results
|
|
154
|
-
- External research only when brain is insufficient
|
|
155
|
-
|
|
156
|
-
### Mid-Conversation
|
|
157
|
-
- Re-scan on topic shift: `notesmd-cli search-content "<new-topic>"`
|
|
158
|
-
|
|
159
|
-
### Session End (mandatory)
|
|
160
|
-
- `notesmd-cli daily` — log: discussion, decisions, intel, actions
|
|
161
|
-
|
|
162
|
-
### Write Immediately When
|
|
163
|
-
- New intel -> `notesmd-cli create "Intelligence/<name>"`
|
|
164
|
-
- Playbook updated -> edit `Playbooks/` note now
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
## Auto-Sync (optional)
|
|
168
|
-
|
|
169
|
-
Push brain changes to GitHub via inotifywait + cron:
|
|
170
|
-
|
|
171
|
-
```bash
|
|
172
|
-
# Watcher (scripts/brain-sync.sh)
|
|
173
|
-
while inotifywait -r -e modify,create,delete ./brain/ 2>/dev/null; do
|
|
174
|
-
cd brain && git add -A && \
|
|
175
|
-
git commit -m "brain: auto-sync $(date +%Y-%m-%d_%H:%M)" && \
|
|
176
|
-
git push && cd ..
|
|
177
|
-
done
|
|
178
|
-
|
|
179
|
-
# Cron fallback (every 30 min)
|
|
180
|
-
# */30 * * * * cd /path/to/workspace && bash scripts/brain-sync.sh >> logs/brain-sync.log 2>&1
|
|
73
|
+
genie brain link --brain <id>
|
|
181
74
|
```
|
|
75
|
+
Generates wikilinks from tag overlap and wikilink references.
|
|
76
|
+
|
|
77
|
+
## How Agents Should Use This
|
|
78
|
+
|
|
79
|
+
### Before answering domain questions:
|
|
80
|
+
1. Search the brain: `genie brain search "<topic>" --brain <my-brain-id>`
|
|
81
|
+
2. Check confidence level
|
|
82
|
+
3. If FULL/HIGH → cite the results
|
|
83
|
+
4. If PARTIAL → use results + note limitations
|
|
84
|
+
5. If NONE → say "brain doesn't cover this" and research externally
|
|
85
|
+
|
|
86
|
+
### After learning something new:
|
|
87
|
+
1. Write a .md file with frontmatter to `brain/to_process/`
|
|
88
|
+
2. Run `genie brain process` to classify and index it
|
|
89
|
+
3. The brain grows over time
|
|
90
|
+
|
|
91
|
+
### Session hygiene:
|
|
92
|
+
- Start: check `genie brain status` for brain health
|
|
93
|
+
- During: search brain before making claims
|
|
94
|
+
- End: write session learnings to brain
|
|
95
|
+
|
|
96
|
+
## Brain Types
|
|
97
|
+
|
|
98
|
+
| Type | Use Case | Base Folders |
|
|
99
|
+
|------|----------|-------------|
|
|
100
|
+
| `gtm` | Marketing, competitive intel | Intelligence/, DevRel/, Company/ |
|
|
101
|
+
| `pm` | Product management | Backlog/, Roadmap/, Specs/ |
|
|
102
|
+
| `engineering` | Architecture, code | Architecture/, Decisions/, Runbooks/ |
|
|
103
|
+
| `research` | R&D, papers | Papers/, Notes/, Experiments/ |
|
|
104
|
+
| `personal` | Personal knowledge (PARA) | Projects/, Areas/, Resources/ |
|
|
105
|
+
| `generic` | Auto-decided by content | (autoschema decides) |
|
|
106
|
+
|
|
107
|
+
## Confidence Levels
|
|
108
|
+
|
|
109
|
+
| Level | Meaning | Agent Action |
|
|
110
|
+
|-------|---------|-------------|
|
|
111
|
+
| **FULL** | Brain knows this well (3+ strong results) | Use directly, cite sources |
|
|
112
|
+
| **HIGH** | Good coverage (2+ results) | Use with confidence |
|
|
113
|
+
| **PARTIAL** | Some info available | Use + supplement if needed |
|
|
114
|
+
| **LOW** | Weak match | Go external, mention brain gap |
|
|
115
|
+
| **NONE** | Brain doesn't know this | Research externally, don't guess |
|
|
116
|
+
|
|
117
|
+
## Available Brains on This Server
|
|
118
|
+
|
|
119
|
+
Run `genie brain status` to see all. Current brains include:
|
|
120
|
+
- **genie-gtm** — Marketing intelligence, competitors, DevRel
|
|
121
|
+
- **vegapunk** — R&D, architecture, code analysis
|
|
122
|
+
- **totvs** — Client project management
|
|
123
|
+
- **sofia** — Personal assistant knowledge
|
|
124
|
+
- **namastex-global** — Company-wide shared knowledge
|
|
182
125
|
|
|
183
126
|
## Rules
|
|
184
|
-
|
|
185
|
-
-
|
|
186
|
-
-
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
- Write intel immediately when discovered — do not batch until session end.
|
|
190
|
-
- Templates live in `skills/brain/templates/`. Copy to `brain/_Templates/` during provisioning.
|
|
127
|
+
- **Search before claiming.** If the brain has an answer, use it.
|
|
128
|
+
- **Respect confidence.** NONE means NONE — don't fabricate.
|
|
129
|
+
- **Write back.** If you learn something the brain should know, add it.
|
|
130
|
+
- **Use frontmatter.** All brain files need YAML frontmatter (type, tags, dates).
|
|
131
|
+
- **Keep it Obsidian-compatible.** Wikilinks, not regular links.
|
|
@@ -25,12 +25,26 @@ async function installBrain(): Promise<boolean> {
|
|
|
25
25
|
console.log('');
|
|
26
26
|
|
|
27
27
|
try {
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
// Verify GitHub CLI is authenticated (no token extraction — gh handles auth securely)
|
|
29
|
+
try {
|
|
30
|
+
execSync('gh auth token', { stdio: 'pipe' });
|
|
31
|
+
} catch {
|
|
32
|
+
console.error(' ✗ GitHub CLI not authenticated. Run: gh auth login');
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Clone brain repo using gh CLI (handles private repos without exposing tokens in process list)
|
|
37
|
+
const brainDir = 'node_modules/@automagik/genie-brain';
|
|
38
|
+
execSync(`rm -rf "${brainDir}"`, { stdio: 'pipe' });
|
|
39
|
+
execSync('mkdir -p node_modules/@automagik', { stdio: 'pipe' });
|
|
40
|
+
execSync(`gh repo clone automagik-dev/genie-brain "${brainDir}" -- --depth 1`, {
|
|
31
41
|
stdio: 'inherit',
|
|
32
42
|
});
|
|
33
43
|
|
|
44
|
+
// Install brain's deps + build
|
|
45
|
+
execSync('bun install', { cwd: brainDir, stdio: 'inherit' });
|
|
46
|
+
execSync('bun run build', { cwd: brainDir, stdio: 'inherit' });
|
|
47
|
+
|
|
34
48
|
console.log('');
|
|
35
49
|
console.log(' ✓ Brain installed from GitHub.');
|
|
36
50
|
console.log('');
|
|
@@ -78,10 +92,11 @@ async function installBrain(): Promise<boolean> {
|
|
|
78
92
|
|
|
79
93
|
function uninstallBrain(): void {
|
|
80
94
|
try {
|
|
81
|
-
|
|
95
|
+
const brainDir = 'node_modules/@automagik/genie-brain';
|
|
96
|
+
execSync(`rm -rf "${brainDir}"`, { stdio: 'pipe' });
|
|
82
97
|
console.log(' ✓ Brain uninstalled.');
|
|
83
98
|
} catch {
|
|
84
|
-
console.error(' Uninstall failed. Manual:
|
|
99
|
+
console.error(' Uninstall failed. Manual: rm -rf node_modules/@automagik/genie-brain');
|
|
85
100
|
}
|
|
86
101
|
}
|
|
87
102
|
|