Skip to content

Core concepts

This page describes the Cordis plugin model and lifecycle state machine.

A service is a capability one plugin exposes to other plugins. inject declares the services a plugin requires.

Events are the core communication mechanism between Cordis plugins. Harness uses them extensively for loosely coupled extension points.

Cordis is the plugin framework underneath DeepSeek Harness: a small runtime where every capability — tools, LLM adapters, file access, the agent loop itself — is a plugin mounted into a shared context. This tutorial teaches Cordis hands-on: each chapter is a runnable example you build in a scratch directory inside this repository, ending with a plugin wired into real harness services.

The audience is agent developers. You do not need deep TypeScript experience; the TypeScript notes below explain the syntax that may be unfamiliar, and every chapter shows the exact commands and expected output.

If you want the condensed concept reference instead of a walkthrough, read the Cordis primer. The exhaustive API reference lives in the generated cordis-surface regions on the subsystem pages and the Cordis core API pages.

To write plugins for the harness itself — loaded from a cordis.yml and driven from the Web UI rather than the launcher below — start from your first Harness plugin.

In the loader configuration used here, a Cordis plugin module named-exports an apply function. When Cordis loads it, it calls apply with a context — the ctx object through which the plugin registers everything it contributes.

A Cordis plugin can be unloaded by a config edit, hot reload, explicit disposal, or loss of a required service. Registrations made through Cordis APIs are effects and are undone when their owning plugin unloads; resources managed outside those APIs must be wrapped in ctx.effect().

A service is a named capability one plugin provides and other plugins consume through ctx. In the harness, ctx.tools, ctx.llm, and ctx.agents are services. A consumer names the capability, such as 'tools', rather than importing its provider, so configuration can select a provider without changing the consumer.

Services support direct calls; events let a plugin announce something without knowing which plugins listen. The harness uses events for interactions such as tool results, model requests, and approval decisions.

Each cordis.yml entry can carry a config block, and the plugin declares a schema that validates it before apply runs. Bad config fails the load with a precise error — the plugin never starts half-configured.

Every capability built so far is a plugin, and cordis.yml selects the application’s plugin tree. This chapter changes that composition, hot-reloads a plugin, and diagnoses a plugin that never loads.

This chapter registers a model-callable tool with the harness’s tools service, executes it through the harness tool pipeline, and observes the result event. It remains keyless and does not call a model.

Cordis is the vendored plugin framework underneath DeepSeek Harness. This primer teaches the Cordis ideas a harness plugin author needs before reading the generated service/event reference on the subsystem pages; the Cordis tutorial walks the same ideas hands-on. The vendored source and sync procedure live in vendor/README.md.

One page per subsystem of the DeepSeek Harness: what it is, the data structures it moves, and — where a ctx service or event scope backs it — a generated Cordis API section carrying its service and event reference. The folder complements architecture.md, which describes behavior across subsystems (the service map, the session/turn/step lifecycle, the event taxonomy); each page here is the reference for one subsystem’s vocabulary and wiring.

PageOwns
core.mdhow packages/core controls the agent loop: the package-by-package loop description, agent creation and ownership (AgentHandle), the Agent handle’s delivery/cancellation/interception contracts, and the repo-wide type patterns (…Map → derived-union, branded ids)
llm-streaming.mdthe packages/llm conversation types — Message/ContentBlock, the assembled model request, the StreamChunk wire protocol and adapter contract, BlockAssembler, and the LlmAdapter provider contract
token-meter.mdimmutable scalar and positional replay measurements with consumed-log revisions
scope.mdscoped registration identity, dispatch carriers, and the owned Scope context
typert.mdRemote invocation descriptors, lookup/Context declarations, Typert registries, and the Host Gateway/Client API boundaries
goal.mdpersisted goal identity, lifecycle snapshots, activation, change records, and round attribution
schedule.mdSession-local reminder records, durable transitions, active views, and ordinary-conversation delivery
commands.mdthe human-command registry service: definitions, adapter discovery, direct invocation, results, and parsing views
session.mdthe full SessionEventMap variant catalog, TurnTrigger/TurnEndReason, deriveMessages(), execution enclosure, and standalone events
persistence.mdthe durability seam: SessionPersistence, JSONL + SQLite backends, session/flush, crash recovery, SessionHeader
settings.mdthe user-settings seam: SettingsNamespace registration, layered resolution (defaults → composition base → user document), owner scopes, hot commits
credentials.mdthe credential seam: CredentialRef references (never values) in configuration, per-operation resolution, UI-safe CredentialInfo, provider source layers
session-query.mdlogical records, bounded exact-event reads, relationship traces, semantic filters/documents, and full-text result pages
feedback.mdlifecycle-bound per-message feedback records, optimistic versions, sidecar persistence, and the Host Remote contract
session-title.mddurable title snapshots, cited source-message seqs, and the asynchronous provider contract
session-reference.mdstructured cross-session references: SessionReferenceInput/Candidate, prepared message contexts, the stable error taxonomy
system-prompt.mdper-assembly context, tool-provider results, prompt sections, and cooperative assembly
tools.mdToolDefinition full fields, the schema DSL, ToolExecution/ToolResult, tool-presentation UI types, and the guarded execution pipeline
user-questions.mdthe UI-backed human question/answer seam: AskUserQuestionRequest, answer/options vocabulary, provider API, error taxonomy
approval.mdthe one-shot user-approval seam: ApprovalRequest, ApprovalOutcome, per-session policy, audit events, and answerer contracts
attachment.mddurable image identity and metadata, validation inputs, verified reads, and the AttachmentStore seam
shell.mdthe bash executor seam: ShellExecRequest/Spec, ShellRunResult, background ShellProcess handles
subprocess.mdthe subprocess seam: fully-explicit SubprocessSpawnSpec, offset-based output readers, unclassified SubprocessOutcome, and the managed DSH_* environment vocabulary
terminal.mdpersistent terminal ids, backend/session contracts, send readiness, bounded reads, and owner-visible snapshots
sandbox.mdper-session policy resolution and the process-confinement seam: file-effect modes, execution/provider policies, ConfinedArgv, enforcement and fail-closed errors
code-runtime.mdthe code-execution seam: CodeRunRequest/Result, binding namespaces, captured logs, the CodeRunFailure taxonomy
extensions.mdversioned dynamic Cordis Plugins and Packages, Host/Client activation, approval, runtime inspection, and lifecycle teardown
filesystem.mdthe filesystem seam: FsTarget, read/write/edit outcomes, observed-file state, FsErrorCode
lsp.mdthe LSP navigation seam: LspQueryRequest/Result, LspProvider/Service, four operations, LspError
skills.mdthe skill service: discovery priority, SkillSummary/SkillDefinition, session-prefix catalog, model-facing skill loading
compaction.mdthe compaction seam: the compaction/* session events, CompactionResult, the CompactionEngine interface
subagent.mdthe subagent seam: the named-provider registry, SubagentStartRequest/Result/Run, the start-time-vs-runtime capability split
web.mdthe web access seam: WebSearchRequest/Result, WebFetchRequest/Result, WebFetchBody, provider availability, WebError
spill.mdthe spill storage seam: SaveTextSpill, SpillOwner/SpillSource, SpillRef, the branded SpillLocator
workflow.mdthe workflow seam: WorkflowStartRequest, WorkflowMeta, WorkflowRun/Result, the workflow/* event payloads, WorkflowError fatality
jobs.mdthe background-job runtime: branded JobIds, the producer contract, consumer views, and ctx.jobs service behavior
permission-presets.mdthe permission-preset layer: PresetSpec/PresetOption, the derived custom state, the log-only permission/preset event
plan.mdplan mode: the log-only plan/mode state, pending-selection flush, PlanModeConfig, the exit_plan_mode review arc
invariants.mdthe runtime-invariant registry: selection Config, InvariantInstaller/InvariantFailure, the empty-companion contract
web-server.mdthe HTTP carrier: WebRouteKind/WebRoute, match order, the claimable fallback seat, index taps
storage.mdthe storage subsystem: the backend contract (StorageBackend), StorageForms, DomainSpec/Domain, domain/changed
workspace.mdthe workspace registry: Workspace/WorkspaceId, registration and resolution, the session cwd relationship
client-modules.mdthe web plugin table: dsh.client declarations, WebBootGraph wire composition, the bundle route and index tap
session-projection.mdthe projection seam: SessionProjectionMap, the pure ProjectionDefinition unit, ProjectionSnapshot’s consistent cut, the change feed
session-telemetry.mdthe outbound session-reporting capability seam: SessionTelemetryRecord/SessionTelemetrySeverity, the SessionTelemetrySink contract, and the session-telemetry/record redact waterfall

Type declarations and their JSDoc on these pages are source-equivalent and drift-checked by pnpm run verify-type-equiv (see development.md). Ordinary blocks preserve complete declarations; public-api blocks preserve body-stripped public class declarations. Cordis services and events use each page’s generated Cordis API section.

A service can be a core spine service, a swappable capability seam, or a bundle/composition point. The graph shows the package that owns the service declaration, known implementation packages, and packages that consume the service directly.

flowchart LR
  pkg_attachment["attachment"]
  svc_attachments["ctx.attachments<br/>Durable binary attachment storage"]
  pkg_attachment_local["attachment-local"]
  pkg_host_runtime["host-runtime"]
  pkg_llm_pi_ai["llm-pi-ai"]
  pkg_llm["llm"]
  svc_llm["ctx.llm<br/>LLM adapter registry"]
  pkg_llm_deepseek["llm-deepseek"]
  pkg_llm_replay["llm-replay"]
  pkg_agent_loop["agent-loop"]
  pkg_compaction_basic["compaction-basic"]
  pkg_token_meter["token-meter"]
  svc_tokenMeter["ctx.tokenMeter<br/>Replay token measurement"]
  pkg_compaction_tool_result_pruner["compaction-tool-result-pruner"]
  svc_toolResultPruner["ctx.toolResultPruner<br/>Model-free tool-result pruning"]
  pkg_session["session"]
  svc_sessions["ctx.sessions<br/>In-memory session store"]
  pkg_agent["agent"]
  pkg_session_persistence["session-persistence"]
  pkg_session_query["session-query"]
  pkg_session_query_sqlite["session-query-sqlite"]
  pkg_subagent_inprocess["subagent-inprocess"]
  pkg_invariants["invariants"]
  pkg_message_feedback["message-feedback"]
  svc_invariants["ctx.invariants<br/>Package-owned invariant registry"]
  pkg_scope["scope"]
  pkg_typert_registry["typert-registry"]
  svc_typert["ctx.typert<br/>Runtime type registry"]
  pkg_typert_loader["typert-loader"]
  pkg_api_gateway["api-gateway"]
  svc_typertGateway["ctx.typertGateway<br/>Typert Host invocation gateway"]
  svc_sessionPersistence["ctx.sessionPersistence<br/>Durable session persistence seam"]
  pkg_session_persistence_jsonl["session-persistence-jsonl"]
  pkg_session_persistence_sqlite["session-persistence-sqlite"]
  pkg_tool_bash["tool-bash"]
  pkg_hooks_claude_code["hooks-claude-code"]
  pkg_hooks_codex["hooks-codex"]
  pkg_settings["settings"]
  svc_settings["ctx.settings<br/>User-settings seam"]
  pkg_settings_file["settings-file"]
  pkg_apiproxy["apiproxy"]
  pkg_credentials["credentials"]
  svc_credentials["ctx.credentials<br/>Credential seam"]
  pkg_credentials_local["credentials-local"]
  pkg_session_telemetry["session-telemetry"]
  svc_sessionTelemetry["ctx.sessionTelemetry<br/>Session telemetry seam"]
  pkg_session_telemetry_otel["session-telemetry-otel"]
  pkg_storage["storage"]
  svc_storage["ctx.storage<br/>Non-session storage hub"]
  pkg_storage_json["storage-json"]
  pkg_storage_sqlite["storage-sqlite"]
  pkg_storage_domain["storage-domain"]
  svc_storageDomain["ctx.storageDomain<br/>Domain data facility"]
  pkg_workspace["workspace"]
  svc_messageFeedback["ctx.messageFeedback<br/>Lifecycle-bound message feedback"]
  svc_workspaceRegistry["ctx.workspaceRegistry<br/>Workspace entity registry"]
  svc_sessionQuery["ctx.sessionQuery<br/>Session reads, traces, filters, and search"]
  pkg_session_reference["session-reference"]
  pkg_tool_session_query["tool-session-query"]
  svc_sessionReferenceResolver["ctx.sessionReferenceResolver<br/>Cross-session snapshot preparation"]
  pkg_session_title["session-title"]
  svc_sessionTitle["ctx.sessionTitle<br/>Log-backed session titles"]
  pkg_session_title_first_prompt_llm["session-title-first-prompt-llm"]
  pkg_session_title_all_prompts_llm["session-title-all-prompts-llm"]
  pkg_system_prompt["system-prompt"]
  svc_systemPrompt["ctx.systemPrompt<br/>System prompt assembly registry"]
  pkg_tools["tools"]
  pkg_tool_fs["tool-fs"]
  pkg_tool_terminal["tool-terminal"]
  pkg_tool_web["tool-web"]
  svc_tools["ctx.tools<br/>Tool registry and guarded execution pipeline"]
  pkg_tool_ask_user["tool-ask-user"]
  pkg_tool_cordis["tool-cordis"]
  pkg_tool_skill["tool-skill"]
  pkg_tool_subagent["tool-subagent"]
  pkg_tool_todo["tool-todo"]
  pkg_user_questions["user-questions"]
  svc_userQuestions["ctx.userQuestions<br/>Human question/answer seam"]
  pkg_plan_mode["plan-mode"]
  svc_planMode["ctx.planMode<br/>Plan collaboration state"]
  pkg_agent_presets["agent-presets"]
  svc_agentPresets["ctx.agentPresets<br/>Per-session agent composition"]
  pkg_commands["commands"]
  svc_commands["ctx.commands<br/>Human command registry"]
  pkg_session_projection["session-projection"]
  svc_sessionProjections["ctx.sessionProjections<br/>Session projection units"]
  pkg_host_apiproxy["host-apiproxy"]
  pkg_session_projection_cache["session-projection-cache"]
  svc_sessionProjectionCache["ctx.sessionProjectionCache<br/>Persisted projection cache"]
  pkg_skill["skill"]
  svc_skills["ctx.skills<br/>Skill provider registry"]
  pkg_skill_badge["skill-badge"]
  pkg_skill_filesystem["skill-filesystem"]
  svc_agents["ctx.agents<br/>Agent service"]
  pkg_acp["acp"]
  pkg_agent_default_model["agent-default-model"]
  svc_agentDefaultModel["ctx.agentDefaultModel<br/>Default Agent model selection"]
  pkg_headless["headless"]
  svc_agentLoop["ctx.agentLoop<br/>Concrete loop driver"]
  pkg_agent_spine_demo["agent-spine-demo"]
  pkg_goal["goal"]
  svc_goals["ctx.goals<br/>Same-session goal domain"]
  pkg_e2b["e2b"]
  svc_e2b["ctx.e2b<br/>E2B sandbox lifecycle owner"]
  pkg_fs_e2b["fs-e2b"]
  pkg_subprocess_e2b["subprocess-e2b"]
  pkg_subprocess["subprocess"]
  svc_subprocess["ctx.subprocess<br/>Subprocess seam"]
  pkg_subprocess_local["subprocess-local"]
  pkg_bash_local["bash-local"]
  pkg_bash_sandbox["bash-sandbox"]
  pkg_terminal_bash["terminal-bash"]
  pkg_lsp_stdio["lsp-stdio"]
  pkg_subagent_acp["subagent-acp"]
  pkg_subagent_codex["subagent-codex"]
  pkg_subagent_claude_code["subagent-claude-code"]
  pkg_shell["shell"]
  svc_shell["ctx.shell<br/>Bash executor seam"]
  pkg_pwsh_local["pwsh-local"]
  pkg_tool_pwsh["tool-pwsh"]
  pkg_shell_env["shell-env"]
  svc_shellEnv["ctx.shellEnv<br/>Managed bash environment registry"]
  pkg_terminal["terminal"]
  svc_terminals["ctx.terminals<br/>Persistent PTY session registry"]
  pkg_sandbox["sandbox"]
  svc_sandbox["ctx.sandbox<br/>Process-sandbox seam"]
  pkg_sandbox_local["sandbox-local"]
  pkg_sandbox_policy["sandbox-policy"]
  svc_sandboxPolicy["ctx.sandboxPolicy<br/>Sandbox policy home"]
  pkg_fs_sandbox["fs-sandbox"]
  pkg_approval["approval"]
  svc_approval["ctx.approval<br/>Approval seam"]
  pkg_permission_presets["permission-presets"]
  svc_permissionPresets["ctx.permissionPresets<br/>Permission presets"]
  pkg_code_runtime["code-runtime"]
  svc_codeRuntime["ctx.codeRuntime<br/>Code-execution seam"]
  pkg_code_runtime_worker["code-runtime-worker"]
  pkg_fs["fs"]
  svc_fs["ctx.fs<br/>Filesystem provider seam"]
  pkg_fs_local["fs-local"]
  pkg_fs_observation_policy["fs-observation-policy"]
  pkg_compaction["compaction"]
  svc_compaction["ctx.compaction<br/>Compaction seam"]
  pkg_subagent["subagent"]
  svc_subagents["ctx.subagents<br/>Subagent provider and continuation service"]
  pkg_subagent_spawn_in_process["subagent-spawn-in-process"]
  pkg_subagent_fork_in_process["subagent-fork-in-process"]
  pkg_subagent_dsh_sdk["subagent-dsh-sdk"]
  pkg_tool_subagent_control["tool-subagent-control"]
  pkg_tool_ralph["tool-ralph"]
  pkg_jobs["jobs"]
  svc_jobs["ctx.jobs<br/>Background job registry"]
  pkg_jobs_local["jobs-local"]
  pkg_tool_jobs["tool-jobs"]
  pkg_web["web"]
  svc_web["ctx.web<br/>Web access provider registry"]
  pkg_web_search_exa["web-search-exa"]
  pkg_web_search_perplexity["web-search-perplexity"]
  pkg_web_search_deepseek["web-search-deepseek"]
  pkg_web_fetch_http["web-fetch-http"]
  pkg_spill["spill"]
  svc_spillStore["ctx.spillStore<br/>Spill storage seam"]
  pkg_spill_local["spill-local"]
  pkg_spill_policy["spill-policy"]
  pkg_directory_picker["directory-picker"]
  svc_directoryPicker["ctx.directoryPicker<br/>Workspace-directory picking seam"]
  pkg_directory_picker_native["directory-picker-native"]
  pkg_directory_picker_browse["directory-picker-browse"]
  pkg_webserver["webserver"]
  svc_webServer["ctx.webServer<br/>HTTP route registration"]
  pkg_connection["connection"]
  pkg_modules["modules"]
  pkg_hmr["hmr"]
  svc_clientModules["ctx.clientModules<br/>Client plugin graph host"]
  pkg_workflow["workflow"]
  svc_workflowEngine["ctx.workflowEngine<br/>Workflow script engine"]
  pkg_workflow_worker_thread["workflow-worker-thread"]
  pkg_tool_workflow["tool-workflow"]
  pkg_lsp["lsp"]
  svc_lsp["ctx.lsp<br/>Language-server navigation seam"]
  pkg_lsp_local["lsp-local"]
  pkg_tool_lsp["tool-lsp"]
  svc_apiProxy["ctx.apiProxy<br/>Host API dispatch"]
  pkg_cordis_host_runner["cordis-host-runner"]
  svc_dynamicCordisRunner["ctx.dynamicCordisRunner<br/>Dynamic Cordis package host runner"]
  svc_cordisInspect["ctx.cordisInspect<br/>Dynamic Cordis inspect registry"]
  pkg_acp --> svc_approval
  pkg_agent --> svc_agents
  pkg_agent_default_model --> svc_agentDefaultModel
  pkg_agent_loop --> svc_agentLoop
  pkg_agent_presets --> svc_agentPresets
  pkg_api_gateway --> svc_typertGateway
  pkg_apiproxy --> svc_apiProxy
  pkg_approval --> svc_approval
  pkg_attachment --> svc_attachments
  pkg_attachment_local --> svc_attachments
  pkg_bash_local --> svc_shell
  pkg_bash_sandbox --> svc_shell
  pkg_code_runtime --> svc_codeRuntime
  pkg_code_runtime_worker --> svc_codeRuntime
  pkg_commands --> svc_commands
  pkg_compaction --> svc_compaction
  pkg_compaction_basic --> svc_compaction
  pkg_compaction_tool_result_pruner --> svc_toolResultPruner
  pkg_cordis_host_runner --> svc_cordisInspect
  pkg_cordis_host_runner --> svc_dynamicCordisRunner
  pkg_credentials --> svc_credentials
  pkg_credentials_local --> svc_credentials
  pkg_directory_picker --> svc_directoryPicker
  pkg_directory_picker_browse --> svc_directoryPicker
  pkg_directory_picker_native --> svc_directoryPicker
  pkg_e2b --> svc_e2b
  pkg_fs --> svc_fs
  pkg_fs_e2b --> svc_fs
  pkg_fs_local --> svc_fs
  pkg_fs_sandbox --> svc_fs
  pkg_goal --> svc_goals
  pkg_invariants --> svc_invariants
  pkg_jobs --> svc_jobs
  pkg_jobs_local --> svc_jobs
  pkg_llm --> svc_llm
  pkg_llm_deepseek --> svc_llm
  pkg_llm_pi_ai --> svc_llm
  pkg_llm_replay --> svc_llm
  pkg_lsp --> svc_lsp
  pkg_lsp_local --> svc_lsp
  pkg_message_feedback --> svc_messageFeedback
  pkg_modules --> svc_clientModules
  pkg_permission_presets --> svc_permissionPresets
  pkg_plan_mode --> svc_planMode
  pkg_pwsh_local --> svc_shell
  pkg_sandbox --> svc_sandbox
  pkg_sandbox_local --> svc_sandbox
  pkg_sandbox_policy --> svc_sandboxPolicy
  pkg_session --> svc_sessions
  pkg_session_persistence --> svc_sessionPersistence
  pkg_session_persistence_jsonl --> svc_sessionPersistence
  pkg_session_persistence_sqlite --> svc_sessionPersistence
  pkg_session_projection --> svc_sessionProjections
  pkg_session_projection_cache --> svc_sessionProjectionCache
  pkg_session_query --> svc_sessionQuery
  pkg_session_query_sqlite --> svc_sessionQuery
  pkg_session_reference --> svc_sessionReferenceResolver
  pkg_session_telemetry --> svc_sessionTelemetry
  pkg_session_telemetry_otel --> svc_sessionTelemetry
  pkg_session_title --> svc_sessionTitle
  pkg_session_title_all_prompts_llm --> svc_sessionTitle
  pkg_session_title_first_prompt_llm --> svc_sessionTitle
  pkg_settings --> svc_settings
  pkg_settings_file --> svc_settings
  pkg_shell --> svc_shell
  pkg_shell_env --> svc_shellEnv
  pkg_skill --> svc_skills
  pkg_skill_badge --> svc_skills
  pkg_skill_filesystem --> svc_skills
  pkg_spill --> svc_spillStore
  pkg_spill_local --> svc_spillStore
  pkg_storage --> svc_storage
  pkg_storage_domain --> svc_storageDomain
  pkg_storage_json --> svc_storage
  pkg_storage_sqlite --> svc_storage
  pkg_subagent --> svc_subagents
  pkg_subagent_acp --> svc_subagents
  pkg_subagent_claude_code --> svc_subagents
  pkg_subagent_codex --> svc_subagents
  pkg_subagent_dsh_sdk --> svc_subagents
  pkg_subagent_fork_in_process --> svc_subagents
  pkg_subagent_spawn_in_process --> svc_subagents
  pkg_subprocess --> svc_subprocess
  pkg_subprocess_e2b --> svc_subprocess
  pkg_subprocess_local --> svc_subprocess
  pkg_system_prompt --> svc_systemPrompt
  pkg_terminal --> svc_terminals
  pkg_terminal_bash --> svc_terminals
  pkg_token_meter --> svc_tokenMeter
  pkg_tools --> svc_tools
  pkg_typert_registry --> svc_typert
  pkg_user_questions --> svc_userQuestions
  pkg_web --> svc_web
  pkg_web_fetch_http --> svc_web
  pkg_web_search_deepseek --> svc_web
  pkg_web_search_exa --> svc_web
  pkg_web_search_perplexity --> svc_web
  pkg_webserver --> svc_webServer
  pkg_workflow --> svc_workflowEngine
  pkg_workflow_worker_thread --> svc_workflowEngine
  pkg_workspace --> svc_workspaceRegistry
  svc_agentDefaultModel --> pkg_headless
  svc_agentDefaultModel --> pkg_host_apiproxy
  svc_agentLoop --> pkg_agent_spine_demo
  svc_agents --> pkg_acp
  svc_agents --> pkg_agent_loop
  svc_agents --> pkg_subagent_inprocess
  svc_apiProxy --> pkg_connection
  svc_approval --> pkg_tool_bash
  svc_approval --> pkg_tools
  svc_attachments --> pkg_host_runtime
  svc_attachments --> pkg_llm_pi_ai
  svc_clientModules --> pkg_hmr
  svc_codeRuntime --> pkg_tools
  svc_compaction --> pkg_compaction_basic
  svc_cordisInspect --> pkg_tool_cordis
  svc_credentials --> pkg_apiproxy
  svc_credentials --> pkg_llm_deepseek
  svc_credentials --> pkg_llm_pi_ai
  svc_directoryPicker --> pkg_apiproxy
  svc_dynamicCordisRunner --> pkg_tool_cordis
  svc_e2b --> pkg_fs_e2b
  svc_e2b --> pkg_subprocess_e2b
  svc_fs --> pkg_tool_fs
  svc_invariants --> pkg_agent
  svc_invariants --> pkg_agent_loop
  svc_invariants --> pkg_scope
  svc_invariants --> pkg_session
  svc_jobs --> pkg_tool_bash
  svc_jobs --> pkg_tool_jobs
  svc_jobs --> pkg_tool_subagent
  svc_jobs --> pkg_tool_terminal
  svc_llm --> pkg_agent_loop
  svc_llm --> pkg_compaction_basic
  svc_lsp --> pkg_tool_lsp
  svc_sandbox --> pkg_bash_sandbox
  svc_sandbox --> pkg_terminal_bash
  svc_sandboxPolicy --> pkg_bash_sandbox
  svc_sandboxPolicy --> pkg_fs_sandbox
  svc_sandboxPolicy --> pkg_terminal_bash
  svc_sessionPersistence --> pkg_agent_loop
  svc_sessionPersistence --> pkg_hooks_claude_code
  svc_sessionPersistence --> pkg_hooks_codex
  svc_sessionPersistence --> pkg_message_feedback
  svc_sessionPersistence --> pkg_session_query
  svc_sessionPersistence --> pkg_session_query_sqlite
  svc_sessionPersistence --> pkg_tool_bash
  svc_sessionProjectionCache --> pkg_host_apiproxy
  svc_sessionProjections --> pkg_host_apiproxy
  svc_sessionProjections --> pkg_session_title
  svc_sessionProjections --> pkg_tool_todo
  svc_sessionQuery --> pkg_session_reference
  svc_sessionQuery --> pkg_tool_session_query
  svc_sessions --> pkg_agent
  svc_sessions --> pkg_agent_loop
  svc_sessions --> pkg_invariants
  svc_sessions --> pkg_message_feedback
  svc_sessions --> pkg_session_persistence
  svc_sessions --> pkg_session_query
  svc_sessions --> pkg_session_query_sqlite
  svc_sessions --> pkg_subagent_inprocess
  svc_settings --> pkg_apiproxy
  svc_settings --> pkg_llm_deepseek
  svc_settings --> pkg_llm_pi_ai
  svc_shell --> pkg_hooks_claude_code
  svc_shell --> pkg_hooks_codex
  svc_shell --> pkg_tool_bash
  svc_shell --> pkg_tool_pwsh
  svc_shellEnv --> pkg_tool_bash
  svc_shellEnv --> pkg_tool_pwsh
  svc_skills --> pkg_tool_skill
  svc_spillStore --> pkg_spill_policy
  svc_storage --> pkg_storage_domain
  svc_storageDomain --> pkg_message_feedback
  svc_storageDomain --> pkg_workspace
  svc_subagents --> pkg_tool_ralph
  svc_subagents --> pkg_tool_subagent
  svc_subagents --> pkg_tool_subagent_control
  svc_subprocess --> pkg_bash_local
  svc_subprocess --> pkg_bash_sandbox
  svc_subprocess --> pkg_lsp_stdio
  svc_subprocess --> pkg_subagent_acp
  svc_subprocess --> pkg_subagent_claude_code
  svc_subprocess --> pkg_subagent_codex
  svc_subprocess --> pkg_terminal_bash
  svc_systemPrompt --> pkg_agent_loop
  svc_systemPrompt --> pkg_tool_fs
  svc_systemPrompt --> pkg_tool_terminal
  svc_systemPrompt --> pkg_tool_web
  svc_systemPrompt --> pkg_tools
  svc_terminals --> pkg_tool_terminal
  svc_tokenMeter --> pkg_compaction_basic
  svc_toolResultPruner --> pkg_compaction_basic
  svc_tools --> pkg_agent_loop
  svc_tools --> pkg_tool_ask_user
  svc_tools --> pkg_tool_bash
  svc_tools --> pkg_tool_cordis
  svc_tools --> pkg_tool_fs
  svc_tools --> pkg_tool_skill
  svc_tools --> pkg_tool_subagent
  svc_tools --> pkg_tool_terminal
  svc_tools --> pkg_tool_todo
  svc_tools --> pkg_tool_web
  svc_typert --> pkg_api_gateway
  svc_typert --> pkg_typert_loader
  svc_userQuestions --> pkg_tool_ask_user
  svc_web --> pkg_tool_web
  svc_webServer --> pkg_connection
  svc_webServer --> pkg_hmr
  svc_webServer --> pkg_modules
  svc_workflowEngine --> pkg_tool_ralph
  svc_workflowEngine --> pkg_tool_workflow
  svc_workspaceRegistry --> pkg_apiproxy
  svc_fs -. event gate .-> pkg_fs_observation_policy
ctx keyRoleOwnerImplementationsDirect consumersCompanion pluginsNote
ctx.attachmentsseamattachmentattachment-localhost-runtime, llm-pi-ai-The host commits accepted images before session events; provider adapters resolve authorized durable references into provider-native content.
ctx.llmseamllmllm-deepseek, llm-pi-ai, llm-replayagent-loop, compaction-basic-Adapters register provider implementations; the loop and compaction call the provider-neutral stream service.
ctx.tokenMetercoretoken-meter-compaction-basic-Owns isolated per-session replay folds; pressure consumers share immutable revisioned measurements.
ctx.toolResultPrunercorecompaction-tool-result-pruner-compaction-basic-Rewrites oversized current tool results through replayable single-node surface replacements before summary compaction.
ctx.sessionscoresession-agent-loop, agent, session-persistence, session-query, session-query-sqlite, subagent-inprocess, invariants, message-feedback-Owns append-only Session instances and emits the durable session event feed.
ctx.invariantscoreinvariants-session, agent, scope, agent-loop-Companion subpaths register owner-local checks; the service owns selection, uniqueness, child fibers, and package-attributed failures.
ctx.typertcoretypert-registry-typert-loader, api-gateway-Plugins register live zod contributions directly or through dsh-typert-loader; the API gateway consumes invocation descriptors and providers, while other runtime consumers query schemas and reflection metadata at their own edges.
ctx.typertGatewaycoreapi-gateway---Associates generated Remote descriptors with live Cordis services, resolves registered identities, and exposes unary calls through the shared Connection RPC carrier.
ctx.sessionPersistenceseamsession-persistencesession-persistence-jsonl, session-persistence-sqliteagent-loop, tool-bash, hooks-claude-code, hooks-codex, session-query, session-query-sqlite, message-feedback-Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time.
ctx.settingsseamsettingssettings-filellm-deepseek, llm-pi-ai, apiproxy-Plugins register namespace schemas and resolve layered values; providers store the raw document. The LLM adapters register their entry config as the composition base under the user section; the web gateway serves redacted layered descriptors and writes the user layer.
ctx.credentialsseamcredentialscredentials-localllm-deepseek, llm-pi-ai, apiproxy-Configuration carries references to secrets; providers own the values. Consumers resolve per operation, so a rotated credential reaches the very next request; the web gateway exposes value-free views and write-only storage.
ctx.sessionTelemetryseamsession-telemetrysession-telemetry-otel--The seam captures, redacts, and hands session records to one backend; nothing else consumes the service — its output leaves the process.
ctx.storageseamstoragestorage-json, storage-sqlitestorage-domain-Backends register side by side under names; data forms (domain first) mount on the hub and translate typed operations into opaque KV-unit primitives.
ctx.storageDomaincorestorage-domain-workspace, message-feedback-Waits for every configured backend, then publishes the domain form as one lifecycle-bound service for typed durable state.
ctx.messageFeedbackcoremessage-feedback---Owns local per-assistant-message feedback, lifecycle and target validation, per-item compare-and-set, and the Host unary Remote contract without entering Session history or telemetry.
ctx.workspaceRegistrycoreworkspace-apiproxy-Owns WorkspaceId-branded records over the domain facility; stable sessionIds accounts drive Host RPC and GUI projections.
ctx.sessionQueryseamsession-querysession-query-sqlitesession-reference, tool-session-query-The interface supplies exact reads, filters, and traces; its concrete backend adds full-text reconciliation, ranking, snippets, and cursor generations, while the model consumer owns workspace authority and cursor-free rendering.
ctx.sessionReferenceResolvercoresession-reference---Projects bounded current-surface conversation snapshots into durable untrusted message context; host adapters own mention syntax.
ctx.sessionTitleseamsession-titlesession-title-first-prompt-llm, session-title-all-prompts-llm--Owns the deterministic fallback, latest-title fold, and sole optional asynchronous provider registration.
ctx.systemPromptcoresystem-prompt-agent-loop, tools, tool-fs, tool-terminal, tool-web-Collects prompt sections and model-facing tool schemas for each step.
ctx.toolscoretools-agent-loop, tool-ask-user, tool-bash, tool-cordis, tool-fs, tool-terminal, tool-skill, tool-subagent, tool-todo, tool-web-Registers capabilities, owns Code Mode transport, and routes calls through pre-policy, monotonic guards, around dispatch, post-policy, and final-result observation.
ctx.userQuestionsseamuser-questions-tool-ask-user-UI front ends provide the active human-answer provider; tool-ask-user pauses a tool call on the provider-neutral ask() promise.
ctx.planModecoreplan-mode---Folds logged plan/mode state, flushes user selections at turn boundaries, renders deployment-owned guidance, registers /plan, and keeps the plan-exit schema stable across transitions.
ctx.agentPresetscoreagent-presets---Discovers preset directories over trusted and user-authored roots and mounts one preset cordis.yml under an agent scope during creation, rejecting a row that never activates or that publishes into the root service realm.
ctx.commandscorecommands---Plugins register direct human commands without sending invocations to the model.
ctx.sessionProjectionscoresession-projection-tool-todo, session-title, host-apiproxy-Domains register state-driven fold units; the eager drive keeps per-session watermark states and api-proxy serves baselines and pushes changed values.
ctx.sessionProjectionCachecoresession-projection-cache-host-apiproxy-Durably checkpoints projection unit states per session (throttled + turn/end/detach mandatory points) and serves the cold-read ladder: cache row + persistence tail replay, so listings never load full logs.
ctx.skillsseamskillskill-badge, skill-filesystemtool-skill-Merges provider skill catalogs; tool-skill renders the session-prefix catalog and loads complete skill bodies.
ctx.agentscoreagent-agent-loop, acp, subagent-inprocess-Owns live Agent handles, the create/resume factory seam, and process-local initiator propagation.
ctx.agentDefaultModelcoreagent-default-model-headless, host-apiproxy-Layers the default ModelSelection through settings so direct and Host-backed Agent entry points share one state owner.
ctx.agentLoopbundleagent-loop-agent-spine-demo-The one concrete loop plugin; extension packages depend on dsh-agent events and services, not on this package.
ctx.goalscoregoal---Folds revisioned objective state from the session log and keeps live continuation activation process-local.
ctx.e2bcoree2b-fs-e2b, subprocess-e2b-Owns one shared E2B SDK handle, remote working directory, and final sandbox disposition so both fundamental E2B providers inhabit the same Linux runtime.
ctx.subprocessseamsubprocesssubprocess-local, subprocess-e2bbash-local, bash-sandbox, terminal-bash, lsp-stdio, subagent-acp, subagent-codex, subagent-claude-code-The bash executors, the PTY shell backend, the LSP host, and the out-of-process ACP, Codex, and Claude Code subagent backends spawn through ctx.subprocess; the service owns process coordinates, tree/session lifetime, stdio dispositions, terminal mechanics, and kill escalation.
ctx.shellseamshellbash-local, bash-sandbox, pwsh-localtool-bash, tool-pwsh, hooks-claude-code, hooks-codex-The model-facing shell tools and hook bridges consume this seam; sandboxed, remote, or PowerShell executors replace bash-local without touching them.
ctx.shellEnvcoreshell-env-tool-bash, tool-pwsh-Plugins declare effect-scoped DSH_* facts; each shell tool collects one trusted snapshot per execution and its executor rebuilds the namespace.
ctx.terminalsseamterminalterminal-bashtool-terminal-The registry owns exact-Agent session identity and cleanup; backends own terminal mechanics, while tool-terminal exposes the owner-scoped model tools.
ctx.sandboxseamsandboxsandbox-localbash-sandbox, terminal-bash-Consumers hand over the exact argv they are about to spawn; same-world backends wrap it under a per-call policy and report enforcement.
ctx.sandboxPolicycoresandbox-policy-bash-sandbox, fs-sandbox, terminal-bash-The one home for the deployment default mode + workspace root; only the sandboxed executor and provider read the service (the tool layers use the pure sandbox/mode fold it also exports). Both enforcing families read it so bash and fs cannot confine to different roots.
ctx.approvalseamapprovalacptools, tool-bash-One-shot permission decisions dispatched over the approval/request waterfall; answerers are listeners (the ACP bridge for its own agents), absence fails closed to unavailable.
ctx.permissionPresetscorepermission-presets---User-facing preset table (workspace-write/danger-full-access) bundling the sandbox-mode and approval-policy knobs; a switch writes one permission/preset event through to both knob events.
ctx.codeRuntimeseamcode-runtimecode-runtime-workertools-Runs one model-written program against host-provided async bindings; backends differ by substrate and language (the tool registry consumes it for Code Mode).
ctx.fsseamfsfs-local, fs-sandbox, fs-e2btool-fsfs-observation-policytool-fs executes read/write/edit through ctx.fs; fs-sandbox fences mutations by the shared sandbox mode; fs-observation-policy contributes observed-state checks through the fs/* event gate.
ctx.compactionseamcompactioncompaction-basiccompaction-basic-The basic backend consumes post-step pressure and request-error recovery events; there is no model-facing compact tool.
ctx.subagentsseamsubagentsubagent-spawn-in-process, subagent-fork-in-process, subagent-acp, subagent-codex, subagent-claude-code, subagent-dsh-sdktool-subagent, tool-subagent-control, tool-ralph-Providers implement transports; the service also owns optional Activation-based continuation orchestration, tool-subagent selects one-shot or continuable delegation, tool-subagent-control delivers follow-ups, and tool-ralph requires one fresh structured-output route.
ctx.jobsseamjobsjobs-localtool-bash, tool-terminal, tool-subagent, tool-jobs-Producers (background bash, PTY sends, and subagent delegations) register running work; tool-jobs is the model-facing controller that reads, lists, and kills it; jobs-local is the process-local registry.
ctx.webseamwebweb-search-exa, web-search-perplexity, web-search-deepseek, web-fetch-httptool-web-Search and fetch providers register into one ctx.web seam; tool-web owns the stable model-facing names.
ctx.spillStoreseamspillspill-localspill-policy-The backend saves oversized tool text and returns a model-facing locator plus retrieval hint; spill-policy is the tools/post-execute consumer that decides when to spill.
ctx.directoryPickerseamdirectory-pickerdirectory-picker-native, directory-picker-browseapiproxy-Discriminated interaction capability: the native backend opens one OS chooser on the host display, the browse backend serves listing/creation primitives for the in-app browser; dual-face backends fill ui-workspace directory-flow slots from their browser halves (no wire advertisement).
ctx.webServercorewebserver-connection, modules, hmr-Plain node:http carrier: named-route registry, index transform taps, and the static dist fallback; web-transport plugins register their own routes.
ctx.clientModulescoremodules-hmr-Composes the DSH_BOOT entry graph from an incremental dsh.client scan, serves plugin bundles, and notifies rebuilt/graph-changed subscribers.
ctx.workflowEngineseamworkflowworkflow-worker-threadtool-workflow, tool-ralph-One engine per context, as in bash, with no named-provider registry; the general workflow and fixed Ralph consumers start runs whose agent() calls fan out through ctx.subagents.
ctx.lspseamlsplsp-localtool-lsp-Provider registration and selection plus normalized query execution over exactly four operations; the seam offers no protocol escape hatch, so a backend translates into the normalized request and result.
ctx.apiProxycoreapiproxy-connection-The transport-agnostic host gateway face: it dispatches browser API calls, and each open host stream subscribes to the events it forwards rather than being pushed to through a broadcast verb.
ctx.dynamicCordisRunnercorecordis-host-runner-tool-cordis-Owns the in-memory definition registry, the vm sandbox for host halves, and the request-run round trip; browser pages reach the same service over the wire through its remote namespace.
ctx.cordisInspectcorecordis-host-runner-tool-cordis-Registers host inspect providers, mirrors the client provider manifest, and routes client queries through the dynamic Cordis transport.

Maintenance mode: hybrid: services are discovered from Cordis declarations; interface/implementation/consumer roles are classified in scripts/gen-doc-graphs.ts with a completeness guard.

This sequence is the visual companion to architecture.md. It keeps durable replay facts on session/event and live control/status on agent/*.

sequenceDiagram
  participant User
  participant Agent
  participant Driver
  participant Hooks as hook listeners
  participant Prompt as ctx.systemPrompt
  participant LLM as ctx.llm
  participant Tools as ctx.tools
  participant Session
  participant SDK as UI or SDK listener
  User->>Agent: followup(content)
  Agent-->>SDK: <code>agent/inbox/spliced</code>
  Agent-->>SDK: <code>agent/inbox/inserted</code> { message }
  Agent->>Driver: queued work wakes driver
  Driver-->>SDK: <code>agent/status</code> running
  Driver->>Session: <code>turn/start</code>
  Note over Agent,Driver: claim pending next-step input plus one queued prompt
  Driver-->>SDK: <code>agent/inbox/spliced</code> pure deletion
  Driver-->>SDK: <code>agent/inbox/claimed</code> { message, turn } per message
  Driver->>Hooks: <code>agent/pre-step</code> waterfall
  Hooks-->>Driver: authoritative reject or enter(messages)
  alt proposed step rejected or pre-step failed
    Driver-->>Driver: claimed batch stays removed, the open turn spends no step
  else enter proposed step
  Driver->>Session: <code>step/start</code>
  Driver->>Session: <code>user/message</code> per entered message
  Driver->>Prompt: <code>system-prompt/assemble</code> waterfall
  Driver->>LLM: <code>agent/request</code> waterfall, then <code>llm/stream</code> waterfall
  LLM-->>Driver: StreamChunk*
  Driver->>Session: <code>assistant/chunk</code>*
  Session-->>SDK: <code>session/event</code> <code>assistant/chunk</code>*
  alt final adapter or terminal in-band request failure
    Driver->>Session: <code>step/end</code>
    Driver->>Hooks: <code>agent/request-error</code> waterfall
    Hooks-->>Driver: return retry action or preserve the original error
  else model request succeeded
  Driver->>Session: <code>assistant/message</code>
  Driver->>Tools: classify pending call by executionMode
  loop barriers and bounded rolling pool, reclassify before start
    opt call starts
      Driver->>Session: <code>tool/call</code>
      Driver->>Tools: ordered pre, concurrent execute
      Tools-->>Session: tool-owned events when applicable
    end
    opt next model-order result ready
      Driver->>Tools: ordered post
      Driver->>Session: <code>tool/result</code>
    end
  end
  Driver->>Session: <code>step/end</code>
  opt natural stop and next-step inbox empty
    Driver->>Hooks: <code>agent/turn-stopping</code> serial terminal checkpoint
  end
  opt next-step input is pending
    Driver-->>Driver: claim pending next-step input
    Driver-->>SDK: <code>agent/inbox/claimed</code> { message, turn } per message
    Driver->>Hooks: <code>agent/pre-step</code> waterfall
    Hooks-->>Driver: authoritative reject or enter(messages)
  end
  end
  end
  Driver->>Session: <code>turn/end</code>
  Driver-->>SDK: <code>agent/status</code> idle

The assistant/message event records every successful provider call, including content-less and max-tokens finishes. Empty content stays out of derived history, while the durable event keeps usage and sourceEventSeqs listing the exact assistant/chunk events, including an explicit empty list.

dsh-compaction-basic uses agent/pre-step for pressure before request derivation and agent/request-error only for canonical context overflow. Once either trigger qualifies, optional tool-result pruning runs before summary selection. Recovery works between the closed failed step and failed turn close, and opens a fresh retry turn only when pruning or summarization advances the surface replacement generation; otherwise the original request error remains authoritative.

The returned agent/pre-step decision is authoritative; listeners wrapping next() preserve downstream messages unless replacement is intentional. Steering and injected context pass through the same waterfall after a later claim operation takes their next-step batch.

SDK users that need replayable transcript data should consume session/event; agent/* is the live coordination API for queue/status, prompt interception, request construction, steering, continuation, and errors.

Maintenance mode: curated Mermaid sequence; exact event signatures live in the generated Cordis catalog.

This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, final-outcome observation, and UI rendering run without changing the loop. The tools/pre-execute waterfall runs first, monotonic guards run next, and the tools/execute and tools/post-execute waterfalls follow; the three waterfalls may transform a call. Definition-owned finalizeContent and tools/result run afterward.

flowchart TD
  model["Assistant message contains tool-call block"]
  toolCall["Session event: <code>tool/call</code><br/>logged before execution"]
  presentCall["UI pending card<br/>presentCall(args)"]
  pre["<code>tools/pre-execute</code> waterfall<br/>hooks, permission, sandbox"]
  guards["Registered monotonic guards<br/>deny or abstain; identity protected"]
  denied["denied or approval refused<br/>tool body skipped"]
  approval["<code>ctx.approval</code> one-shot prompt<br/>absent or unanswerable: deny"]
  around["<code>tools/execute</code> waterfall<br/>timeout, retry, metrics (around dispatch)"]
  toolBody["Registered tool execute() body"]
  fsGate["<code>fs/write-intent</code> or <code>fs/edit-intent</code><br/>tool-fs mutations only"]
  owned["Tool-owned session events<br/><code>todo/write</code>, <code>fs/observed</code>, <code>hook/invoked</code>, <code>hook/result</code>, <code>tool/code-dispatch</code>"]
  post["<code>tools/post-execute</code> waterfall<br/>accept, block, replace, add context"]
  normalized["Registry outer normalization<br/>pipeline/result snapshot throws become isError"]
  finalize["ToolDefinition.finalizeContent<br/>last content-only invariant"]
  final["<code>tools/result</code> synchronous notification<br/>frozen authoritative outcome"]
  context["Active-batch additionalContexts FIFO<br/>injected user/message after recorded tool results"]
  toolResult["Session event: <code>tool/result</code><br/>single model-facing outcome"]
  allResults["Tool batch settled<br/>recorded tool/result events complete"]
  presentResult["UI completed card<br/>presentResult(args, result)"]
  model --> toolCall
  toolCall --> presentCall
  toolCall --> pre
  pre -->|allow| guards
  guards -->|allow| around
  guards -->|deny| denied
  guards -.->|throw| normalized
  around --> toolBody
  pre -->|deny| denied
  pre -->|ask| approval
  approval -->|allowed-once| guards
  approval -->|rejected, cancelled, unavailable| denied
  approval -.->|throw| normalized
  denied --> post
  pre -.->|throw| normalized
  toolBody --> fsGate
  fsGate --> toolBody
  toolBody --> owned
  toolBody --> around
  around --> post
  around -.->|wrapper throws| normalized
  post -.->|throw| normalized
  post --> finalize
  normalized --> finalize
  finalize --> final
  final --> toolResult
  toolResult --> presentResult
  toolResult --> allResults
  allResults --> context

Filesystem read-before-edit checks stay below tool-fs on fs/* events. Generic pre/post waterfalls host hooks and approval policy; ctx.approval resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap tools/execute. The registry losslessly snapshots the candidate result and normalizes a snapshot failure before the visible definition’s snapshotted finalizeContent callback enforces its synchronous content-only invariant. tools/result then observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved run_code transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log tool/code-dispatch, return denials as binding rejections, and omit additionalContexts to preserve call/result adjacency.

Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs.