@@ -1081,7 +1081,10 @@ export class AutohandAgent {
10811081 llm : this . llm ,
10821082 workspaceRoot : runtime . workspaceRoot ,
10831083 model : model ,
1084- resetConversation : async ( ) => this . resetConversationContext ( ) ,
1084+ resetConversation : async ( ) => {
1085+ await this . resetConversationContext ( ) ;
1086+ await this . injectSessionBootstrap ( ) ;
1087+ } ,
10851088 undoFileMutation : ( ) => this . files . undoLast ( ) ,
10861089 removeLastTurn : ( ) => this . conversation . removeLastTurn ( ) ,
10871090 // Status command context
@@ -1344,6 +1347,10 @@ export class AutohandAgent {
13441347 this . sessionManager . createSession ( this . runtime . workspaceRoot , model ) ,
13451348 ] ) ;
13461349
1350+ // Inject explicit session bootstrap so the LLM is consciously aware of
1351+ // memories, AGENTS.md, skills, and project context from the first turn.
1352+ await this . injectSessionBootstrap ( ) ;
1353+
13471354 // Phase 3: Telemetry (no stdout output)
13481355 if ( session ) {
13491356 await this . telemetryManager . startSession (
@@ -1408,6 +1415,8 @@ export class AutohandAgent {
14081415 this . sessionManager . createSession ( this . runtime . workspaceRoot , model ) ,
14091416 ] ) ;
14101417
1418+ await this . injectSessionBootstrap ( ) ;
1419+
14111420 // Start telemetry session
14121421 if ( session ) {
14131422 await this . telemetryManager . startSession (
@@ -1531,6 +1540,7 @@ If lint or tests fail, report the issues but do NOT commit.`;
15311540 const session = await this . sessionManager . loadSession ( sessionId ) ;
15321541
15331542 await this . resetConversationContext ( ) ;
1543+ await this . injectSessionBootstrap ( ) ;
15341544 const messages = session . getMessages ( ) ;
15351545 for ( const msg of messages ) {
15361546 if ( msg . role === 'system' ) {
@@ -2541,14 +2551,19 @@ If lint or tests fail, report the issues but do NOT commit.`;
25412551 this . persistentInput . stop ( ) ;
25422552 this . persistentInputActiveTurn = false ;
25432553 }
2544- // Stop Ink renderer if active — it holds stdin/stdout and will
2545- // swallow quality check output or cause stdin conflicts with spawn.
2546- if ( this . useInkRenderer ) {
2547- this . cleanupUI ( ) ;
2554+ // Pause Ink renderer instead of destroying it. This releases stdin/stdout
2555+ // so spawned child processes (lint, test) work correctly, but preserves
2556+ // state so the composer reappears immediately after quality checks.
2557+ if ( this . useInkRenderer && this . inkRenderer ) {
2558+ this . inkRenderer . pause ( ) ;
25482559 }
25492560 cleanupConsoleBridge ( ) ;
25502561 cleanupConsoleBridge = ( ) => { } ; // Prevent double-cleanup in finally
25512562 await this . runQualityPipeline ( ) ;
2563+ // Resume Ink so the composer is restored before runInstruction returns.
2564+ if ( this . useInkRenderer && this . inkRenderer ) {
2565+ this . inkRenderer . resume ( ) ;
2566+ }
25522567 }
25532568 } catch ( error ) {
25542569 success = false ;
@@ -6488,6 +6503,71 @@ If lint or tests fail, report the issues but do NOT commit.`;
64886503 this . updateContextUsage ( this . conversation . history ( ) ) ;
64896504 }
64906505
6506+ /**
6507+ * Generate an explicit session bootstrap note that surfaces the most
6508+ * important context — memories, AGENTS.md, skills, and project structure —
6509+ * as a coherent "here's what you should know" block. This is injected as a
6510+ * system note so the LLM explicitly sees it, rather than passively hoping it
6511+ * notices buried system prompt content.
6512+ */
6513+ private async generateSessionBootstrap ( ) : Promise < string > {
6514+ const parts : string [ ] = [ '[Session Bootstrap]' ] ;
6515+
6516+ // 1. Top memories (most relevant, limited to save tokens)
6517+ const memories = await this . memoryManager . getContextMemories ( 3 ) ;
6518+ if ( memories ) {
6519+ parts . push ( '' , '## Memories & Preferences' , memories ) ;
6520+ }
6521+
6522+ // 2. AGENTS.md summary (first 20 lines — enough for conventions, not the full manifesto)
6523+ const agentsPath = path . join ( this . runtime . workspaceRoot , 'AGENTS.md' ) ;
6524+ if ( await fs . pathExists ( agentsPath ) ) {
6525+ const content = await fs . readFile ( agentsPath , 'utf-8' ) ;
6526+ const summary = content . split ( '\n' ) . slice ( 0 , 20 ) . join ( '\n' ) ;
6527+ if ( summary . trim ( ) ) {
6528+ parts . push ( '' , '## Project Instructions (AGENTS.md)' , summary ) ;
6529+ }
6530+ }
6531+
6532+ // 3. Active skills
6533+ const activeSkills = this . skillsRegistry . getActiveSkills ( ) ;
6534+ if ( activeSkills . length > 0 ) {
6535+ parts . push ( '' , '## Active Skills' ) ;
6536+ for ( const skill of activeSkills ) {
6537+ parts . push ( `- **${ skill . name } **: ${ skill . description } ` ) ;
6538+ }
6539+ }
6540+
6541+ // 4. Lightweight project scan — key config files and top-level structure
6542+ const keyFiles = [ 'package.json' , 'README.md' , 'tsconfig.json' , ' Cargo.toml' , 'pyproject.toml' , 'go.mod' ] ;
6543+ const foundKeys : string [ ] = [ ] ;
6544+ for ( const file of keyFiles ) {
6545+ if ( await fs . pathExists ( path . join ( this . runtime . workspaceRoot , file . trim ( ) ) ) ) {
6546+ foundKeys . push ( file . trim ( ) ) ;
6547+ }
6548+ }
6549+ if ( foundKeys . length > 0 ) {
6550+ parts . push ( '' , `## Project Structure` , `Key files detected: ${ foundKeys . join ( ', ' ) } ` ) ;
6551+ }
6552+
6553+ return parts . join ( '\n' ) ;
6554+ }
6555+
6556+ /**
6557+ * Inject the session bootstrap into the conversation. Called once per
6558+ * session start (new CLI invocation, /new, /clear, or resumed session).
6559+ */
6560+ private async injectSessionBootstrap ( ) : Promise < void > {
6561+ try {
6562+ const bootstrap = await this . generateSessionBootstrap ( ) ;
6563+ if ( bootstrap && bootstrap . length > '[Session Bootstrap]' . length + 10 ) {
6564+ this . conversation . addSystemNote ( bootstrap , '[Session Bootstrap]' ) ;
6565+ }
6566+ } catch {
6567+ // Bootstrap is best-effort; never block session start
6568+ }
6569+ }
6570+
64916571 private availableProviders ( ) : ProviderName [ ] {
64926572 const providers : ProviderName [ ] = [ ] ;
64936573 if ( this . runtime . config . openrouter ) providers . push ( 'openrouter' ) ;
0 commit comments