This file provides guidance to Claude Code (claude.ai/code) and other coding
agents when working in this repository. It is the single authoritative index
for the project — there is no separate llm.txt or AGENTS.md.
CLAUDE.md is the project index. Treat it as an index, not a dump: every
section should answer "where to look" + "what it does". Whenever you change
architecture, commands, settings, file locations, feature behavior, MCP tools,
validation behavior, or test layout, you must update CLAUDE.md in the same
change.
Update CLAUDE.md if any of these change:
- new feature/module added or removed
- files moved/renamed
- command IDs or settings added/changed/removed
- MCP tools/schemas/names/logging changed
- data persistence locations changed (
.vscode/*, project file semantics) - build/test commands or test structure changed
How to update: scan the affected files in src/, package.json, and test/;
update only the relevant sections; keep file paths and behavior summaries
correct; avoid speculative or outdated statements. If uncertain, state the
assumption explicitly rather than leaving stale content. For MCP, point to the
canonical files (src/mcp/soarMcpTools.ts, src/mcp/soarMcpServer.ts,
src/mcp/soarMcpCore.ts, src/mcp/mcpRegistration.ts) instead of duplicating
full contracts.
Soar language support in VS Code with:
- syntax highlighting
- language server integration
- datamap editing and validation
- VisualSoar project structure editing
- project creation/sync/validation
- MCP server for LLM/agent workflows
- socket-based debug adapter integration for remote Soar kernel control (SML XML)
npm install # Install dependencies
npm run compile # Type-check + bundle all three entry points to dist/
npm run watch # Watch mode (runs esbuild watch + tsc watch in parallel)
npm run lint # ESLint on src/
npm run lint:fix # ESLint with auto-fix
npm run format # Prettier on src/, *.md, *.json
npm run format:check # Check formatting without writing
npm test # Unit tests (mocha, no VS Code required) — fast feedback loop
npm run test:ci # Integration tests (headless VS Code environment)
npm run package # Production build
npm run vsce:package # Package as .vsix
npm run changelog # Regenerate CHANGELOG.md from git history (git-cliff)Releases are tag-driven. Run one of:
npm version patch # or: minor | major | <explicit version>This triggers the npm version lifecycle:
preversion— runsnpm run lint && npm test- bumps
package.json/package-lock.json version— regeneratesCHANGELOG.mdviagit-cliff --tag <new version>and stages it into the version commit- npm creates the commit + tag (no
vprefix; enforced by.npmrctag-version-prefix=""so tags match the CI*.*.*trigger) postversion—git push --follow-tags
Pushing the tag runs the release job in .github/workflows/ci.yml, which packages the VSIX and creates a GitHub Release with notes from git-cliff --latest.
Run a single unit test file:
npx mocha --ui tdd -r ts-node/register test/helpers/index.ts test/lsp/datamap/helpers/datamap.test.tsThe pre-commit hook (npm run precommit) runs format, lint, and markdown lint — these are enforced before every commit.
Three separate esbuild bundles are produced into dist/:
extension.js— VS Code extension host entry (src/extension.ts)server.js— LSP language server (src/server/soarLanguageServer.ts)mcpServer.js— Standalone MCP stdio server (src/mcp/soarMcpServer.ts)
tsc (via compile-server) compiles everything to out/ and is what the unit tests use via ts-node. The dist/ bundles are what VS Code actually runs.
src/extension.ts is the single wiring point: registers all commands, wires tree view providers, sets up the LSP client, installs validation-on-save triggers (respecting .soarignore), registers the debug adapter for soar-sml, and runs the MCP auto-registration hook. It also invalidates the .soarignore cache via a FileSystemWatcher + soarIgnoreCache module variable.
Project state is modeled as a ProjectContext (defined in src/server/visualSoarProject.ts), containing the parsed .vsa.json, a datamapIndex: Map<string, DMVertex>, and a layoutIndex: Map<string, LayoutNode>. This object is the shared currency passed across all subsystems.
- Extension entrypoint:
src/extension.ts - Types and project schema model:
src/server/visualSoarProject.ts - Project load/save + schema validation:
src/server/projectLoader.ts - Shared ID generation helper:
src/server/idGeneration.ts— canonicalgenerateVertexIdused across datamap/layout/MCP flows
| Area | Key files | Responsibility |
|---|---|---|
| Project I/O | src/server/projectLoader.ts |
Load/save .vsa.json, build indices |
| Project discovery | src/projectManager.ts |
Scan for .vsa.json, manage active project, persist to .vscode/soar-active-project.json |
| LSP server | src/server/soarLanguageServer.ts, soarParser.ts |
Parse Soar productions, provide diagnostics |
| LSP client | src/client/lspClient.ts |
Bridge extension ↔ server |
| Datamap tree | src/datamap/datamapTreeProvider.ts |
Tree rendering, cycle detection, search/sort |
| Datamap CRUD | src/datamap/datamapOperations.ts |
Add/edit/delete attributes; deleteAttributeCore (no UI) used by both UI path and MCP |
| Datamap validation | src/datamap/datamapValidator.ts |
Validate .soar files against datamap; creates VS Code diagnostics |
| Datamap integrity | src/datamap/datamapMetadata.ts |
DatamapMetadataCache.checkLinkedAttributeIntegrity — dangling/unreachable edge detection |
| Layout tree | src/layout/layoutTreeProvider.ts, layoutOperations.ts |
Project structure CRUD |
| Project sync | src/layout/projectSync.ts |
Find/import orphaned .soar files; respects .soarignore |
.soarignore |
src/layout/soarIgnore.ts |
Gitignore-semantics file exclusion (ignore npm package) |
| Project creation | src/layout/projectCreator.ts |
Creates new project, writes default .soarignore |
| Undo/redo | src/layout/undoManager.ts |
Undo stack for layout+datamap ops |
| Debug adapter | src/debug/soarSmlDebugAdapter.ts, smlSocketClient.ts |
DAP↔SML XML socket bridge for live Soar kernel debugging |
| Stop phase view | src/debug/stopPhaseTreeProvider.ts |
Sidebar for selecting Soar stop phase |
| MCP server | src/mcp/soarMcpServer.ts, soarMcpTools.ts, soarMcpCore.ts |
Exposes project/datamap/runtime tools over MCP stdio |
| MCP registration | src/mcp/mcpRegistration.ts |
Writes MCP entry to .vscode/mcp.json and .mcp.json |
| ID generation | src/server/idGeneration.ts |
generateVertexId() — shared canonical hex-string ID generator |
generateVertexIdfromsrc/server/idGeneration.tsis the single source for new vertex/node IDs. Use it everywhere — not inline Math.random or uuid.deleteAttributeCoreindatamapOperations.tsis the pure (no-UI) deletion path. Both the interactive command and MCP delegate to it.- MCP per-project serialization:
soarMcpServer.tsserializes concurrent tool calls perprojectFileviatoolExecutionQueue.tsto prevent load/modify/save races. .soarignore: New projects get a default.soarignore. Orphan-file discovery and datamap validation both respect it.- Prefer reusing existing core logic (especially in datamap and project loader flows) rather than creating parallel implementations.
src/projectManager.ts- project discovery (
.vsa.jsonscanning) - active project selection/restore/clear
- active-project persistence for MCP:
.vscode/soar-active-project.json - project validation diagnostics (missing/orphaned files)
- orphaned-file diagnostics respect
.soarignore(viaProjectSync)
- project discovery (
src/datamap/datamapTreeProvider.ts- datamap tree rendering and root switching
- search filter:
setSearchFilter(text)/searchFilter— filters children by attribute name; toggled viasoar.searchDatamap/soar.clearDatamapSearchcommands; VS Code context keysoar.datamapSearchActivedrives toolbar icon swap - sort mode:
setSortEnabled(bool)/sortEnabled— sorts children by type priority (SOAR_ID → ENUMERATION → INTEGER → FLOAT → STRING → JAVA_FILE) then alphabetically; toggled viasoar.toggleDatamapSort/soar.disableDatamapSort; VS Code context keysoar.datamapSortEnabled
src/datamap/datamapOperations.ts- add/edit/delete attributes
- edit flow supports updating enumeration values (e.g.,
^impassechoices) - edit flow supports parent reassignment:
Change Parent: move attribute (and referenced subtree) to a new SOAR_ID parentChange Parent + Link: move ownership and keep a linked reference on previous parent
- linked attribute operations
- uses shared
generateVertexIdfor new datamap vertices - datamap persistence and metadata refresh
src/datamap/datamapMetadata.ts- ownership/link metadata, inbound edge maps, path/attribute helpers
src/datamap/datamapValidator.ts- validates Soar attributes against datamap
- variable binding/path checks
- enum value validation
- infers
<s>state context from explicit^nametests and, when needed, from layout file location (high-level operator substate ancestry) - VS Code diagnostics creation (with non-VSCode-safe fallback used by MCP)
src/datamap/datamapMetadata.ts- ownership/link metadata, inbound edge maps, path/attribute helpers
DatamapMetadataCache.checkLinkedAttributeIntegrity(project, datamapIndex)— static method; returnsDatamapIntegrityIssue[]with two kinds:dangling: edge whosetoIdis not present in the datamap index at allunreachable-root: linked attribute (shared-target edge) whose target vertex cannot be reached from the datamap root via the ownership DFS
DatamapIntegrityIssuecarrieskind,parentVertexId,attributeName,targetVertexId, and a human-readablemessage- called automatically by
validateProjectAgainstDatamap(result appears inValidationSummary.datamapIssues) and exposed standalone via the MCP tooldatamap_check_integrity
- Deletion clean-up (
src/datamap/datamapOperations.ts):DatamapOperations.removeVertexRecursive(public static): two-pass strategy — collect full subtree IDs, then sweep every SOAR_ID vertex and strip any outgoing edge pointing into the deleted set, preventing dangling link edges after an owned-vertex deletionDatamapOperations.deleteAttributeCore(context, parentVertexId, attributeName, removeLinkOnly?)(public static): pure deletion logic with no VS Code UI calls. Removes the named edge from the parent, determines ownership viaownerParentIdfrom edge metadata, callsremoveVertexRecursivewhen appropriate, saves the project, and returns{ parentVertexId, attributeName, targetVertexId, removedAsLinkOnly }. Used directly by tests and delegated to by both the UI path and MCP layer.DatamapOperations.deleteAttribute(public static): UI path — shows a confirmation dialog (showWarningMessage) then delegates todeleteAttributeCoreSoarMcpCore.deleteAttribute: thin wrapper — loads context, delegates toDatamapOperations.deleteAttributeCore
src/layout/layoutTreeProvider.tssrc/layout/layoutOperations.ts- uses shared
generateVertexIdwhen creating datamap vertices for layout-driven edits
- uses shared
src/layout/projectSync.ts- shared project-file gathering helpers (including existing
.soarcollection) reused by project-wide datamap validation flows findOrphanedFiles()loads.soarignoreviasoarIgnore.tsand skips matching files before returning
- shared project-file gathering helpers (including existing
src/layout/soarIgnore.tsloadSoarIgnore(projectRoot)– reads.soarignore(next to.vsa.json) using gitignore semantics (ignorenpm package); returns anIgnoreinstance (empty = nothing ignored if file absent)isIgnoredByPatterns(ig, relativePath)– returns true if the path should be excludedDEFAULT_SOARIGNORE_CONTENT– template written to new projects
src/layout/projectCreator.ts- creates a default
.soarignorefile in the project root on project creation
- creates a default
src/layout/undoManager.ts
src/server/soarParser.tssrc/server/soarLanguageServer.tssrc/client/lspClient.ts
src/debug/smlSocketClient.ts- strongly typed SML XML socket client
- 4-byte big-endian length framing
- call/response correlation via
ack - auto-reply for inbound
doctype=callmessages - persistent socket behavior (no user-configurable idle timeout)
src/debug/soarSmlDebugAdapter.ts- inline DAP adapter implementation (
vscode.DebugAdapter) - DAP→SML mapping for initialize/launch/threads/stackTrace/scopes/variables/continue/next/stepIn/stepOut/pause/evaluate/disconnect
- DAP thread model maps one thread per Soar agent discovered from
get_agent_list - DAP call stack maps to goal-stack states per selected thread/agent and is recomputed on stop/stack requests; frames are returned current→root so VS Code auto-selects current state
- stable identity maps preserve deterministic IDs across session lifetime: agent→threadId, state→frameId, objectKey→variablesReference
- advertises DAP
supportsInvalidatedEventand emitsinvalidated(all) after each stop to force Watch/Variables/UI refresh scopesreturnsWorking Memory,Operator, andIO Linksections for each selected state frame- Variables section targets:
Working Memoryusesprint <state> -d <printDepth> -t,Operatorusesprint <o> -d <printDepth> -t, andIO Linkusesprint I1 -d <printDepth> -t - Variables depth is user-configurable via debug configuration
printDepth variablesresolves structured WMEs (identifier-expansion via stable references) from section/identifier contexts- always emits an initial
stoppedevent on connect to select first stack frame automatically - stop transitions (
entry/step/pause) emitpreserveFocusHint: falseso VS Code focuses the newest selected frame - no editable Variables entries; command interaction is handled via Watch/Debug Console evaluate requests
- applies configurable
printDepth(-d) andprintTree(-t) formatting to Variables and Watch print rendering - watch evaluation is frame-context aware (
frameId→state) and returns stable identifier references when possible - watch evaluation is fault-tolerant: retries once on transient post-step failures and returns
<unavailable: ...>value (success response) instead of DAP error - execution mapping uses
cmdline runfor continue andcmdline stopon pause when session is running evaluateforwards Debug Console (replcontext) input directly as Soar CLI command text and resolves non-REPL expressions in frame context- supports custom request
soarSetVariablesDepthto update Variables depth at runtime and emitinvalidatedfor variables - debug configuration provider + descriptor factory for debug type
soar-sml
- inline DAP adapter implementation (
src/debug/stopPhaseTreeProvider.ts- sidebar tree data provider for stop-phase selection with phases
input,proposal,decision,apply,output - defaults selection to
apply(Soar default stop-before phase) - parses status output from
soar stop-phase(Stop before <phase>) for UI synchronization - tracks selected phase in-view and executes
soar.setStopPhasecommand from tree items
- sidebar tree data provider for stop-phase selection with phases
src/mcp/soarMcpTools.ts- MCP tool definitions and schemas
src/mcp/soarMcpServer.ts- MCP stdio server and request handlers
- project-scoped tool calls are serialized per
projectFileto prevent concurrent load/modify/save races
src/mcp/soarMcpCore.ts- reusable core operations invoked by MCP tools
datamap_update_attribute_edgesupports enum value updates via optionalenumChoicesfor enumeration targets (including impasse value sets)- generates VisualSoar-style hex string IDs for new datamap vertices and layout nodes
- owns persistent SML runtime bridge state for MCP (
agent_runtime_connectlifecycle, current agent tracking,soarCycleExecuting/paused state) agent_runtime_connectprobes kernelversionandget_agent_listimmediately after socket connect; initial agent-list probe depends on connected client state (not pre-existing session state)- executes Soar runtime commands over socket via
SmlSocketClient
src/mcp/toolExecutionQueue.ts- keyed async execution queue used by MCP server for safe parallelism
src/mcp/mcpRegistration.ts- workspace MCP registration: writes BOTH
.vscode/mcp.json(VS Code native client,serverskey) and project-root.mcp.json(Claude Code,mcpServerskey) - writes MCP server command as
node <extension>/dist/mcpServer.js SOAR_MCP_WORKSPACEis set to a portable placeholder, not an absolute path:${workspaceFolder}in.vscode/mcp.json,${CLAUDE_PROJECT_DIR:-.}in.mcp.json. The server (resolveWorkspaceRootinsoarMcpCore.ts) falls backSOAR_MCP_WORKSPACE→CLAUDE_PROJECT_DIR→process.cwd().
- workspace MCP registration: writes BOTH
For MCP details (tool names, payloads, logging, and active-project behavior), start in those four files.
Current MCP coverage includes datamap CRUD, datamap structural integrity checks, project-vs-datamap validation, active-project lookup, layout node lookup, layout additions (operator/impasse operator/file/folder), and remote runtime control for running kernels via SML socket:
layout_find_nodes— find layout nodes bynodeId(exact) orname(case-insensitive substring match); optionaltypefilter andincludeChildrenflag; returns{ matches: LayoutNodeDetail[] }where each entry hasid,type,name,parentNodeId,filePath(resolved absolute),folderPath(resolved absolute for folder/container nodes), anddmId(datamap vertex ID when present). Primary use: discoverparentNodeIdvalues before calling add-* tools, or resolve file paths for nodes by name.agent_runtime_connect/agent_runtime_disconnectagent_runtime_get_status— returns{ running: bool, soarCycleExecuting: bool, host, port, currentAgent };runningis true when the connection is alive;soarCycleExecutingis true only while decision cycles are executingagent_runtime_list_agentsagent_runtime_run_decision_cycles/agent_runtime_step_decision_cycles/agent_runtime_pause— these returnsoarCycleExecuting(notisRunning) in their resultagent_runtime_exec_cli— generic CLI escape hatch for advanced/large-context LLMs- Individual Soar CLI command tools (for smaller/local LLMs that need explicit schemas):
agent_runtime_cli_production—production <subcommand>(break/excise/find/firing-counts/matches/memory-usage/optimize-attribute/watch)agent_runtime_cli_print—print [options] [target](working memory, production memory, stack, GDS)agent_runtime_cli_preferences—preferences [options] [identifier [attribute]]agent_runtime_cli_epmem—epmem [subcommand](enable/disable/get/set/stats/timers/viz/print/backup)agent_runtime_cli_explain_track_operator—explain track-operator [<name>|--all](track one operator, track all, or list tracked operators)agent_runtime_cli_explain_untrack_operator—explain untrack-operator <name|all>(exclude one operator from tracking, or disable all-mode)agent_runtime_cli_explain_operator—explain operator <name> [--json](decision-cycle explanation data for tracked operators)
See package.json (contributes/commands/configuration) and src/extension.ts (runtime command wiring).
- Legacy smoke-test command
soar.helloWorldhas been removed from bothpackage.jsoncontributions andsrc/extension.tsregistrations. soar.validateSelectedProjectAgainstLspruns LSP-based checks across all existing project.soarfiles (project-wide Problems panel refresh).soar.checkDatamapIntegrityrunsDatamapMetadataCache.checkLinkedAttributeIntegrityon the active project and shows a summary notification; a "Show Details" action opens a plaintext report listing every issue by kind, attribute name, and vertex IDs. The command is also exposed as an icon button in the Datamap view title bar.
Debug contract additions:
package.jsoncontributes debugger typesoar-smlwith launch attributes:host,port,agent,printDepth,printTree,stopOnEntry(stopOnEntryretained for compatibility; adapter auto-stops on connect)src/extension.tsregisters debug configuration provider and debug adapter descriptor factory forsoar-smlpackage.jsoncontributessoarStopPhasesidebar view and commandssoar.setStopPhase/soar.refreshStopPhaseView/soar.setVariableViewDepthsoarStopPhaseis contributed to VS Code's built-in Debug view container (not the custom Soar activity container)src/extension.tswires stop-phase selection to activesoar-smlsessions via DAPevaluatewithcontext: repl, issuingsoar stop-phase <phase>and queriessoar stop-phaseon debug-start/refresh to reflect current kernel statesrc/extension.tsexposes runtime Variables depth control (soar.setVariableViewDepth) via custom requestsoarSetVariablesDepthon the activesoar-smlsession
.vsa.json (VisualSoar schema version 6) is the canonical project file. It contains both the datamap graph (vertices with typed edges) and the layout tree (operators, files, folders). Compatible with VisualSoar 9.6.4.
| What | Where |
|---|---|
| Project file | .vsa.json next to the agent's source files |
| Active project (MCP) | .vscode/soar-active-project.json |
| MCP server registration | .vscode/mcp.json (VS Code) + .mcp.json (Claude Code) |
Datamap and layout persist into the project file directly.
- Build:
npm run compile - Watch:
npm run watch - Lint:
npm run lint - Unit tests:
npm test - VS Code integration tests:
npm run test:ci - Markdown lint ignores
CHANGELOG.mdandCLAUDE.mdvia.markdownlintignore - GitHub tag release workflow (
.github/workflows/ci.yml,releasejob): packages VSIX, generates latest release notes via git-cliff (cliff.toml,--latest) intorelease-notes.md, and publishes withsoftprops/action-gh-releaseusingbody_path- changelog entries include a short linked commit SHA to the repository commit URL
Unit tests use mocha with ts-node directly — no VS Code needed. Test bootstrap is test/helpers/index.ts (sets up the VS Code mock at test/helpers/vscode-mock.ts).
| Test area | Location |
|---|---|
| LSP/datamap validation | test/lsp/datamap/helpers/ |
| Datamap integrity + deletion | test/lsp/datamap/helpers/datamap-integrity.test.ts (uses DatamapMetadataCache, DatamapOperations.deleteAttributeCore, ProjectLoader directly — no MCP dependency) |
| Linked attributes | test/lsp/datamap/helpers/linked-attributes.test.ts |
| Parent reassignment | test/datamap-manipulation/fixtures/parent-reassignment.test.ts |
| Layout operations / undo | test/layout/ |
| MCP tools | test/mcp/helpers/ (queue safety in tool-execution-queue.test.ts; ID format regression in id-generation.test.ts; enum update coverage in update-attribute.test.ts) |
| Completions | test/lsp/completions/helpers/ |
| Legacy project compatibility | test/legacy-agents/ |
| Integration (VS Code host) | test/integration/ — run via npm run test:ci |
| Manual debug launch setups | test/.vscode/launch.json (Extension Host launch + soar-sml socket debug config for local end-to-end adapter checks) |
When asked to modify behavior, first map the request to one of the sections above and open those files before changing code. Prefer reusing existing core logic (especially in datamap and project loader flows) rather than creating parallel implementations.