session_handoff
Capture and restore development session context by automatically recording git state, completed tasks, next steps, and blockers for continuity between work sessions.
Instructions
Write a session handoff primer that auto-captures git state (branch, last 5 commits, modified files), last completed task, next step, and blockers. The next session reads this automatically for seamless context continuity.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| lastTask | No | What was completed this session | |
| nextStep | No | Exact next action for the next session | |
| blockers | No | Open blockers or unresolved issues | |
| openFiles | No | Key files being worked on | |
| project | No | Project name (auto-detected from cwd if omitted) | |
| customContext | No | Any additional context for the next session |
Implementation Reference
- scripts/contextfs.js:814-877 (handler)The actual implementation of the 'session_handoff' tool logic, which captures git state and writes a primer.json file for session continuity.
function writeSessionHandoff({ project, branch, lastTask, nextStep, blockers, openFiles, customContext } = {}) { ensureDir(path.join(CONTEXTFS_ROOT, NAMESPACES.session)); let gitContext = {}; try { const { execSync } = require('child_process'); const cwd = process.cwd(); gitContext = { branch: branch || execSync('git rev-parse --abbrev-ref HEAD', { cwd, encoding: 'utf8' }).trim(), lastCommits: execSync('git log --oneline -5', { cwd, encoding: 'utf8' }).trim().split('\n'), modifiedFiles: execSync('git diff --name-only HEAD~1 2>/dev/null || echo ""', { cwd, encoding: 'utf8' }).trim().split('\n').filter(Boolean), status: execSync('git status --short', { cwd, encoding: 'utf8' }).trim().split('\n').filter(Boolean), }; } catch (_) { gitContext = { branch: branch || 'unknown', lastCommits: [], modifiedFiles: [], status: [] }; } const primer = { id: `session_${Date.now()}_${crypto.randomBytes(3).toString('hex')}`, timestamp: nowIso(), project: project || path.basename(process.cwd()), git: gitContext, lastTask: lastTask || null, nextStep: nextStep || null, blockers: Array.isArray(blockers) ? blockers : (blockers ? [blockers] : []), openFiles: Array.isArray(openFiles) ? openFiles : [], customContext: customContext || null, }; const primerPath = path.join(CONTEXTFS_ROOT, NAMESPACES.session, 'primer.json'); fs.writeFileSync(primerPath, JSON.stringify(primer, null, 2)); // Sync to primer.md if it exists const mdPrimerPath = path.join(process.cwd(), 'primer.md'); if (fs.existsSync(mdPrimerPath)) { try { let md = fs.readFileSync(mdPrimerPath, 'utf8'); if (primer.lastTask) { md = md.replace(/## Last Completed Task\n- .*/, `## Last Completed Task\n- ${primer.lastTask}`); } if (primer.nextStep) { md = md.replace(/## Exact Next Step\n- .*/, `## Exact Next Step\n- ${primer.nextStep}`); } if (primer.blockers.length > 0) { md = md.replace(/## Open Blockers\n(?:- .*\n)*/, `## Open Blockers\n${primer.blockers.map(b => `- ${b}`).join('\n')}\n`); } fs.writeFileSync(mdPrimerPath, md); // Trigger full memory refresh (Layer 3, 4, 5) const { execSync } = require('child_process'); execSync('./bin/memory.sh', { stdio: 'ignore' }); } catch (e) { console.error('Warning: Failed to sync to primer.md:', e.message); } } recordProvenance({ action: 'session_handoff', source: 'session', detail: `Handoff: ${primer.lastTask || 'no task'} → ${primer.nextStep || 'no next step'}`, }); return primer; } - scripts/tool-registry.js:468-480 (registration)Registration of the 'session_handoff' tool, including its schema and description.
destructiveTool({ name: 'session_handoff', description: 'Write a session handoff primer that auto-captures git state (branch, last 5 commits, modified files), last completed task, next step, and blockers. The next session reads this automatically for seamless context continuity.', inputSchema: { type: 'object', properties: { lastTask: { type: 'string', description: 'What was completed this session' }, nextStep: { type: 'string', description: 'Exact next action for the next session' }, blockers: { type: 'array', items: { type: 'string' }, description: 'Open blockers or unresolved issues' }, openFiles: { type: 'array', items: { type: 'string' }, description: 'Key files being worked on' }, project: { type: 'string', description: 'Project name (auto-detected from cwd if omitted)' }, customContext: { type: 'string', description: 'Any additional context for the next session' }, }, - adapters/mcp/server-stdio.js:446-447 (handler)MCP tool dispatch logic calling the writeSessionHandoff handler.
case 'session_handoff': return toTextResult(writeSessionHandoff(args));