SponsorLobeHubLobeHubLearn more
dshfind

Lesson 10: The Code Map: Navigating the Project Structure

In one sentence: DSH is a monorepo — apps/ holds the entry points (cli, web, acp), packages/ holds all the capabilities (each package is a swappable plugin brick), and docs/ is the manual; whatever capability you are looking for, go to the package with the matching name under packages/xxx, and with the "ctx key → package → responsibility" table in docs/architecture.zh.md plus the module-graph dependency graph, the whole repo becomes navigable like a map.


1. User Story: The First Day with the Repo

Little D cloned the DSH source repo and stood in front of the root directory, a bit lost: a pile of files and directories at the root, with no idea where to start. He really only had two questions:

  1. "How does DSH actually run? Where is the entry point?"
  2. "I want to swap out a capability of the agent (for example, change the sandbox or add a search tool). Which directory should I go to?"

A veteran only told him one sentence: **First recognize the three top-level directories — apps, packages, docs; then remember one navigation rule — whatever capability you want, go find the package with the matching name under packages. Then he pointed him to a table in docs/architecture.zh.md, and both questions were solved.

This lesson expands on "that one sentence from the veteran" and explains it clearly. After reading it, when you face this repo you will know at least three things: where the entry point is, where the capabilities are, and how to look up dependencies.


2. The Monorepo Panorama: apps Is the Entry, packages Is the Capability, docs Is the Manual

First, look at the repo root (source: ls of the repo root). The top level is not a pile of scattered files but three blocks with clear divisions of labor:

Top-level directoryRoleWhat's inside
apps/Entry point (things that can be started)cli (the dsh command itself), web (the browser side of the Web UI); the automation entry point ACP lives at packages/acp and can be started with pnpm run demo:acp (source: root README.zh.md)
packages/All capabilities (plugin bricks)200+ packages spread across 49 "capability groups", e.g. core/, shell/, sandbox/, skill/, web/, llm/
docs/Manual (architecture, tutorials, maps)architecture.zh.md, module-graph.md, graph-atlas.md, tool-catalog.md, etc.
仓库根apps/ 入口cli · web · acppackages/全部能力家族docs/ 文档架构·教程·指南core/ 核心agent · sessiontools · system-prompt能力家族(接缝)bash · sandbox · skill · web · lspsubagent · workflow · session-query想找什么能力 → 找对应 packages/xxx每个包都是独立可替换的插件

apps 是入口,packages/core 是默认流程,其余全是可替换的能力插件

How to read it: apps/ decides "how to start", packages/ decides "what capabilities exist", docs/ decides "where to look things up".

The three entry points each have their own job:

  • Command line: apps/cli is the dsh command itself. The docs define it as "the product launcher for profiles" (source: apps/cli/README.zh.md) — dsh web, dsh --profile headless "task" are all parsed by it, which then starts plugins combined per profile.
  • Web UI: apps/web is the browser side (a Vite project, source: apps/web/ directory), working together with packages/host (the GUI host half: API gateway + HTTP routing) and packages/client (the browser half: shell, protocol layer, ui-* plugins).
  • Automation: packages/acp is an ACP (Agent Client Protocol) server "for automation only" (source: packages/acp/README.zh.md), exposing agents to programmatic clients through a standardized protocol.

🎁 Analogy: apps are the "power button", packages are "the ingredients in the fridge", docs are "the recipe book". Press the power button, pick ingredients, consult the recipe — the three things never interfere with each other. This is exactly what "everything is a plugin" looks like projected onto the directory structure.


3. Two Navigation Lines: core's Default Flow + the Seams of Capability Families

3.1 The First Line: packages/core Is the Default Flow

Once inside packages/, the first directory to recognize is core/. The package index doc calls it the "product API backbone": session logs, system prompt assembly, the tool registry, agent vocabulary, default model selection, the concrete loop — "constituting the harness's default control backbone" (source: packages/core/README.zh.md). It contains only 7 packages:

Packages in coreResponsibility (ctx key in parentheses)
scope/Scope context registration primitives (library, no ctx key)
session/Event-sourced session logs and in-memory storage (ctx.sessions)
system-prompt/Registry for assembling prompts and tool schemas (ctx.systemPrompt)
tools/Scoped tool registry and execution pipeline (ctx.tools)
agent/Agent interface, registry, and event vocabulary (ctx.agents)
agent-default-model/Default model selection shared by agent entry points (ctx.agentDefaultModel)
agent-loop/Default concrete agent driver (ctx.agentLoop)

A one-sentence memory hook: core is the minimal skeleton that gets an agent running — session, prompts, tools, agent, model, loop, all right here. The concepts from previous lessons land on these 7 packages in the code.

3.2 The Second Line: All Other packages Are "Swappable Capability Families" (Seams)

Beyond core there are dozens of packages, which are not the core flow but capabilities the core flow can plug in and out. The architecture doc puts it this way: "packages/core/ brings together the default flow; the individual capabilities still exist as plugins" (source: docs/architecture.zh.md). Each capability is a "seam": the capability definition, provider, and consumer are separated, and any end can be replaced on its own (echoing "capability as seam" from Lesson 1).

Capability family (seam)What it does (source: the hierarchy table in packages/README.zh.md)
llm/LLM capability family: abstract services + provider adapters
shell/Bash capability family: executor seam, local/sandboxed/PowerShell implementations, model-facing tools
terminal/Persistent PTY family: owner-isolated sessions, local implementation, and terminal_* tools
code-runtime/Code execution family: Service Definition + worker-thread provider + the Code Mode consumer
sandbox/Process confinement seam: bwrap / Landlock / Seatbelt backends
fs/Filesystem: seam, local implementation, model-facing file tools, discovery tools backed by packaged ripgrep
lsp/LSP semantic navigation: seam, generic stdio provider and lsp tool
skill/Skills: provider registry, filesystem provider, catalog and loader
web/Web capabilities: search and fetch provider implementations, model-facing Web tools
subagent/, workflow/, jobs/, goal/, schedule/Collaboration and task management (delegation, multi-agent orchestration, background jobs, persistent goals, in-session scheduling)
session/, session-query/Persisted session data plane, session retrieval
storage/, spill/, attachment/Non-session storage hub, oversized tool-output spill, durable attachments
typert/, api/, sdk/, acp/, mcp/The outward protocol surface: type-graph RPC, BFF gateway, JSON-RPC SDK, ACP server, MCP client
host/, client/The host half and the browser half of the Web GUI

The navigation rule is hidden in this table: whatever capability you want, go find the package with the matching name under packages/ — want to swap the sandbox? packages/sandbox. Want to add search? packages/web. Want to study skill loading? packages/skill. The name is the index.

3.3 Table-Based Navigation: A Three-Layer Index (Architecture Doc → Group README → Subsystem Page)

The directory names alone are not enough — a single capability group may hold several services. DSH now splits "looking things up" into three layers, each owning one segment:

Layer 1: the "Core packages" table in docs/architecture.zh.md. It keeps only the seven spine rows, answering "who is the minimum needed to run an agent":

PackageOwnsctx key
core/sessionThe append-only SessionEvent log and in-memory storectx.sessions
core/system-promptPrompt-section and tool-schema assemblyctx.systemPrompt
core/toolsThe scoped tool registry and guarded execution pipelinectx.tools
core/agentThe Agent interface, live registry, and agent/* eventsctx.agents
core/agent-loopThe default driver implementing that interfacectx.agentLoop
core/scopeThe per-agent scoped-registration primitivelibrary, no ctx key
llm/llmMessage and stream vocabulary plus the adapter seamctx.llm

Layer 2: the group README is the authority for ctx-key mapping. The package index doc says it plainly: "the group README is responsible for the package/ctx key mapping" (source: packages/README.zh.md). So to find which packages a capability has and which ctx key each hangs on, open packages/<group>/README.zh.md rather than going back to the architecture doc. The common ones:

ctx keyPackage groupResponsibility
ctx.shellshell/Foreground command execution and background process starts
ctx.terminalsterminal/Owner-isolated persistent PTY sessions
ctx.jobsjobs/The kind-agnostic background-job registry
ctx.sandboxsandbox/Restricting processes via argv wrapping and per-call policies
ctx.fsfs/Executing-world paths, bounded I/O, and policy events
ctx.skillsskill/Skill provider registry and progressive disclosure
ctx.webweb/Search and fetch provider registry
ctx.subagentssubagent/Named delegation providers
ctx.workflowEngineworkflow/Script-driven multi-agent orchestration
ctx.compactioncompaction/When to compact history and how to summarize it
ctx.codeRuntimecode-runtime/Running model-written programs (the backend of Code Mode)
ctx.sessionQuerysession-query/Bounded reads and retrieval over the session corpus
ctx.storage / ctx.spillStorestorage/ / spill/Non-session storage hub / oversized-output spill

Layer 3: the subsystem pages under docs/subsystems/. There are now 40-odd of them, one per capability (shell.md, terminal.md, jobs.md, code-runtime.md, session-query.md, spill.md, typert.md, …), each carrying a generated Cordis API region — go straight here when you want a capability's complete types and events.

💡 One naming convention that saves a lot of guessing: the repository now has an explicit naming contract — a singular ctx key means one engine / runtime / policy / controller; a plural ctx key means a registry, and the class's role name must agree with the key's number. So ctx.workflowEngine tells you it is an engine (not a registry), while ctx.terminals, ctx.agents, and ctx.jobs tell you they own many named members. In the same spirit, local is used only when same-host execution is part of the contract — which is why the fetch implementation is web-fetch-http (named by protocol) rather than web-fetch-local, and the LSP provider is lsp-stdio (named by transport) rather than lsp-local.

How to use it:

  • Forward lookup: you see ctx.tools, ctx.sandbox in plugin code and want to know which package implements it → look up the package group by ctx key → read the group README → go to docs/subsystems/<capability>.md when you need detail.
  • Reverse lookup: you want to replace a capability → find the package group in the table → go to the packages/<group>/<pkg> directory, reading the group's README first and then individual packages.

4. Reading Dependencies from Graphs: module-graph and graph-atlas

The last tool in the kit is graphs. The docs put it plainly: the graphs under docs/ "form a relationship layer above the generated directories" — to figure out dependencies between packages, you don't need to dig through code by hand, just look at the graphs (source: docs/graph-atlas.zh.md).

docs/module-graph.md (module dependency graph): automatically generated by a tool from each package's peerDependencies (the canonical runtime dependency signal), grouped hierarchically by packages/<group>/<pkg>; each edge a --> b means "package a depends on package b" (source: docs/module-graph.zh.md). Note how to read it: the package names in the graph have the @deepseek-ai/dsh- prefix stripped. To regenerate, run pnpm run gen-module-graph — and CI has a "freshness gate": commits are blocked when the graph is stale (source: the dependencies section of packages/README.zh.md).

docs/graph-atlas.md (atlas of doc graphs): a list of graphs that organizes the scattered graphs into an "atlas": the module dependency graph, the tool schema catalog with package mappings (tool-catalog.md), capability seams and core services (capability-seams.md), application composition graph, the event producer/consumer matrix, the agent turn and step lifecycle, the tool execution pipeline (source: docs/graph-atlas.zh.md).

💡 Practical tip: before changing packages/fs, first check who depends on it in the module graph — if both bash and sandbox point to it, you know the blast radius of your change; if you want to know "which steps exactly does an agent go through in one turn", look at the agent lifecycle graph. The atlas is the catalog for "finding graphs"; module-graph is the graph for "finding dependencies".


Key Points Recap

  1. Three top-level directories: apps/ is the entry point (cli, web, acp), packages/ is all the capabilities, docs/ is the manual.
  2. packages/core is the default flow: the seven-piece set of scope, session, system-prompt, tools, agent, agent-default-model, agent-loop is the minimal skeleton that gets an agent running.
  3. All other packages are swappable capability families (seams): navigation rule = whatever capability you want → go find the package with the matching name under packages/xxx; the name is the index.
  4. Table-based navigation (three layers): the "Core packages" table in docs/architecture.zh.md covers the seven spine rows; the group README is the authority for the package/ctx key mapping; docs/subsystems/<capability>.md gives one capability's complete types and events.
  5. Reading dependencies from graphs: module-graph.md shows package dependencies (tool-generated, kept fresh by CI); graph-atlas.md is the index of these graphs.

🚀 Starting next lesson, we go deep into the code with this map in hand: beginning with packages/core/agent-loop — how the default loop actually "spins up".

Self-Test · Code Map

Answer each question, then submit to check your result.

1. What are the roles of the three top-level directories apps, packages, and docs in the DSH repo?
2. Which statement about packages/core is correct?
3. You want to give the agent a new sandbox implementation. According to DSH's navigation rule, where should you look?
4. In the code you see ctx.agents, ctx.tools, and ctx.agentLoop and want to reverse-look-up which package provides each of them. What is the most appropriate approach?