How seek works under the hood.
seek 的底层工作原理。
seek doesn't start from zero every session. Three layers of persistence capture knowledge at different timescales:
seek 不会每次会话从零开始。三层持久化以不同时间尺度捕捉知识:
~/.seek/soul.md. Cross-project user preferences and thinking habits. ~500 token hard cap, resident in system prompt. Written by seek -dream → user review.~/.seek/projects/<hash>/memory.jsonl. Key decisions and rationale per project. Index injected into every prompt; full content fetched on demand via memory_recall.~/.seek/sessions/<id>.jsonl (or $SEEK_HOME/sessions/). Full message history with auto-save. /distill at session end extracts reusable decisions into M.pkg/agent/memory/ · internal/memory/ · docs/guide-memory.mdAfter R1 refactor, permission lives on two orthogonal axes — never crammed into a single enum:
R1 重构后,权限走两条正交轴——不再合并成一个 enum:
Deny / Ask / Yolo) — your standing posture. "How strict am I." Chosen at startup (--yolo, --no-perm) or toggled via /yolo.None / PlanAnalyze / PlanExecute) — the ceremony you've entered. "What am I doing." Toggled via /plan and the propose-tool flow.Workflow trumps Preference where they conflict. PrefYolo + WorkflowPlanAnalyze is still read-only — that's plan mode's raison d'être. The workflow is a user-chosen safety boundary; pref can't override it.
Workflow 永远 trump Preference。PrefYolo + WorkflowPlanAnalyze 仍然是只读——这正是 plan mode 存在的意义。Workflow 是用户选定的安全边界,pref 不能反过来覆盖。
Permission denials are tool results, not errors — the agent sees the denial message and asks the user (or reconsiders), rather than crashing the loop.
权限拒绝是工具结果,而非错误——agent 看到拒绝消息后会询问用户(或重新考虑),而不是中断循环。
internal/permission/ · see docs/prd/feature-permission-refactor.mdseek exposes tools to the LLM as JSON schema definitions. Current tools:
seek 以 JSON schema 定义向 LLM 暴露工具。当前工具列表:
read / grep / list_dir — filesystem exploration (grep first, read offset-limited segments)write / edit — file mutation (edit requires exact old_string, unique match)bash / git — shell + git porcelain (denied without --yolo or in plan-analyze workflow)fim_complete — DeepSeek-specific fill-in-the-middle (cheaper than chat for small gaps)think — DeepSeek reasoning mode for planning and self-reviewwebfetch — HTTPS GET with SSRF guard (works in plan-analyze; private-IP + redirect-target validation)mcp — bridge to external MCP servers (stdio / SSE / WebSocket transports)ask_user — open a TUI picker to gather user choice mid-loopSkill / skill_fetch / skill_commit — discover, install, and invoke skillsmemory_observe / memory_recall / memory_amend / memory_archive — M-layer read/writepropose / plan — plan-mode v2 confirmation-gated workflow (analyze → propose → execute → adjust → report)agent / enter_worktree / exit_worktree — spawn subagents (v5 柱 G); marked ReadOnly so multiple agent calls dispatch in parallelschedule_wakeup — model self-schedules a future check-in (v5 柱 H one-shot cron)Key constraint: Tool schemas are []byte constants at package level (built once at init, not at call time). This ensures identical bytes across turns → DeepSeek's prefix cache hits.
关键约束:工具 schema 是包级别的 []byte 常量(在 init 时构建一次,而非每次调用)。这确保跨轮次的字节一致性,从而命中 DeepSeek 的前缀缓存。
internal/tools/ · each tool in its own package with a New(...) constructorDeepSeek charges ~10× less per token on cache hits. The cache key is an exact byte sequence of the entire prior message history. This drives several architecture decisions:
DeepSeek 对缓存命中收取约 1/10 的价格。缓存键是完整历史消息的精确字节序列。这驱动了以下架构决策:
internal/pricing/ · pkg/deepseek/ (cache stats in API response)seek is DeepSeek-first but provider-agnostic. The architecture splits into two tiers:
seek 以 DeepSeek 为第一优先,但与 Provider 无关。架构分为两层:
pkg/deepseek — first-class client with DeepSeek-specific fields: cache metadata, FIM endpoint, reasoner content. Zero external dependencies.pkg/llm — thin generic interface for Anthropic, OpenAI, Gemini, and OpenAI-compatible endpoints.Critical rule (CI-enforced): pkg/deepseek must not import pkg/llm. DeepSeek-specific optimisations must never be lowered into a generic interface.
关键规则(CI 强制):pkg/deepseek 不能导入 pkg/llm。DeepSeek 专属优化绝不能被降级到通用接口中。
pkg/deepseek/ · pkg/llm/ · pkg/agent/ (type switch between tiers)Sessions are stored as JSONL files (schema_version=2):
会话以 JSONL 格式存储(schema_version=2):
loadMeta() reads only this line — no need to load the full file for the session list.deepseek.Message per line in JSON./branch forks to a new file; /compact summarises old history.f.Sync() before f.Close().internal/session/ · docs/guide-sessions.md/plan is more than read-only exploration. The model analyzes context, proposes a problem definition + step list via the propose tool, waits for user approve / adjust / cancel, then enters EXECUTE substate with per-step gating via the plan tool.
/plan 不只是只读探索。模型分析上下文 → 通过 propose 工具提议问题定义 + step list → 等待用户 approve / adjust / cancel → 进入 EXECUTE 子态,通过 plan 工具按步审批。
seek -resume by replaying propose args + plan(start|complete|skip) events. No parallel state file.seek -resume 通过 replay propose 参数 + plan(start|complete|skip) 事件重建子态,无并行状态文件。~/.seek/projects/<id>/plans/. Audit trail of "at moment X, approved these steps for problem Y."~/.seek/projects/<id>/plans/。"在 X 时刻、对 Y 问题、批准了哪几步"的审计记录。N/M progress.N/M 进度。internal/tools/propose/ · internal/tools/plan/ · docs/prd/feature-plan-mode.mdThe parent agent can spawn subagents — each with its own session, token budget, and optionally an isolated git worktree — to run parallel research, drafting, or experimentation. Only the summary crosses back, so the parent's prefix cache stays warm.
父 agent 可派生子代理——各自独立 session、token 账户,可选 git worktree 隔离——并行调研、起方案或试验。只有 summary 回到父,父的 prefix cache 不被击穿。
Pref × Workflow can only be tighter than the parent's. Policy.Spawn(restriction) enforces it at the type level.Pref × Workflow 只能比父更严。Policy.Spawn(restriction) 在类型层强制。cache.Tracker.AdoptChild wires the child's per-turn usage into the parent's cumulative cost. Status bar shows the full picture.cache.Tracker.AdoptChild 把子的每轮 token 累加到父的 cumulative cost。状态栏展示完整画面。agent tool is marked ReadOnly so multiple agent calls in one assistant turn run concurrently, not sequentially.agent 工具标 ReadOnly,让一轮多个 agent 调用并行跑,不串行。seek runs no resident daemon. Scheduling delegates to the OS (launchd / systemd / cron / Task Scheduler), which invokes seek cron tick once a minute. tick reads jobs.jsonl + triggers/, fires what's due, exits.
seek 零常驻 daemon。调度委派给 OS(launchd / systemd / cron / Task Scheduler),每分钟调用 seek cron tick。tick 读 jobs.jsonl + triggers/,触发所有到期,退出。
seek cron create), model self-scheduled wakeups (schedule_wakeup tool, max_runs=1), and external triggers (CI / IDE writes JSON to ~/.seek/cron/triggers/).seek cron create)、模型自调用唤醒(schedule_wakeup 工具,max_runs=1)、外部触发(CI / IDE 写 JSON 到 ~/.seek/cron/triggers/)。~/.seek/cron/env overlay (dotenv format) supplies DEEPSEEK_API_KEY and friends. Parse errors fail spawn loudly.~/.seek/cron/env 覆盖文件(dotenv 格式)注入 DEEPSEEK_API_KEY 等。解析错误明确报错。osascript ✅ / Linux notify-send ✅ (auto no-op when headless) / Windows ⚠️ no-op pending BurntToast adapter (v0.6.x dot).osascript ✅ / Linux notify-send ✅(headless 自动 no-op)/ Windows ⚠️ no-op,BurntToast 适配在 v0.6.x dot。runs/<id>.jsonl keeps 100 recent + 30 days max-age; .malformed/ keeps 20 recent + 14 days. Suffix filter ensures live <job>.lock files in runs/ are NEVER deleted.runs/<id>.jsonl 保留 100 个最近 + 30 天最老;.malformed/ 保留 20 个最近 + 14 天。后缀过滤确保 runs/ 中活跃的 <job>.lock 文件永远不被删。