Skip to content

Track session CWD in WorkingContext and emit as [working-context] + [project-instructions] #595

Description

@Aaronontheweb

Summary

When a Netclaw session is working on a specific project directory, it needs to:

  1. Carry a CurrentWorkingDirectory field in SessionState.WorkingContext.
  2. Re-read project-scoped identity files (.netclaw/AGENTS.md, CLAUDE.md, AGENTS.md) on every turn, walking up from the CWD so project instructions survive compaction and stay current as CWD changes mid-session.

Not in scope here: making tool calls respect the session CWD. That's tracked separately — see the paired issue "Resolve shell + file tool paths against session CWD".

Why this is separate from the working-context-grounding OpenSpec change

Scope protection. The durable task-state change (WorkingContext with RecentFiles / OpenGoals / ProgressMarkers) should not gate on the CWD tracking, and CWD tracking has its own design questions:

  • Where does CWD come from when the session is created?
  • Who sets it — user command? session-join metadata? tool-call side effect?
  • Precedence when multiple project identity files exist at different levels of the directory tree
  • Backward compat with sessions that have no CWD set

Reference implementations

  • OpenCode packages/opencode/src/session/instruction.ts:127-135, 164-178findUp walker for AGENTS.md / CLAUDE.md / CONTEXT.md. First match wins at each level. Framing: Instructions from: {path}\n{content}.
  • Claude Code memory docs — project-root CLAUDE.md is re-injected from disk after compaction. Nested CLAUDE.md files only re-inject when a file in that subdirectory is read. OpenCode's walker is the cleaner simplification.

Acceptance criteria

  • WorkingContext.CurrentWorkingDirectory field added, settable via a session-level API and persisted in SessionSnapshot + SessionCompacted event.
  • [working-context] block emitted by InjectDynamicContextLayers includes CWD.
  • New [project-instructions] block emitted by InjectDynamicContextLayers, populated by walking up from CWD to find project identity files, framed as Instructions from: {path}\n{content}.
  • Project identity files re-read from disk on every turn (EveryTurn semantics).
  • Compaction does not affect the block — it is always current on the next FireLlmCall. Integration test forces a compaction and asserts the block is still present with correct content.
  • Regression test: session at CWD=X gets CLAUDE.md from X injected; switching CWD to Y mid-session picks up Y's CLAUDE.md on the next turn.
  • Backward compat: sessions without a CWD set continue to work; the [project-instructions] block is simply empty.

Background

Filed as a follow-up to the compaction architecture rework. The failing Slack session on 2026-04-11 lost grounding about the project it was working on after compaction. The structured summary in the compaction-rework change gets us 80% of the way there; project identity file re-reading closes the remaining gap for sessions that shift context across projects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    context-pipelineLLM context assembly: prompt layers, dynamic injection, memory recall, temporal groundingenhancementNew feature or requestsessionsLLM session actor, turn lifecycle, pipelines

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions