No description.

chezmoi と home-manager (Nix) ベースで構築された個人用dotfiles.
.chezmoiroot # chezmoi/ をソースディレクトリとして指定
chezmoi/ # chezmoi 以下が同期される設定ファイル群
dot_agents/ # → ~/.agents
dot_claude/ # → ~/.claude
dot_zshrc.tmpl # → ~/.zshrc
private_dot_config/ # → ~/.config/
home-manager/ # home-manager 設定
shell/ # 共有シェルスクリプト (.zshrc から読み込み)
scripts/ # セットアップ・メンテナンス用スクリプト
config/ # $HOME 以下に同期はしない設定ファイル (starship, MCP)
bash -c "$(curl -fsLS https://raw.githubusercontent.com/d-kimuson/dotfiles/refs/heads/main/scripts/setup.sh)"
上記を実行することで
の流れでセットアップが完了。
exec $SHELL -l
でシェル設定も読み込んでおく。
dotfiles-apply
chezmoi apply + home-manager switch + シェル再読み込みが実行される。
./scripts/update.sh
mise, direnv, zed-editor は stable pin、それ以外は主に unstable を利用している。
shell/localrc.sh を追加し、環境変数等追加したい設定を記載
export TERM=xterm-256color
internal-cli mcp deliver
internal-cli pi-agent deliver
internal-cli merge-config
internal-cli mcp deliver: config/mcp.template.json を各種 MCP 設定へ配布~/.pi/agent/ は必要に応じて自動作成~/.claude.json~/Library/Application Support/Claude/claude_desktop_config.json~/.codex/config.toml~/.pi/agent/mcp.jsonconfig/pi-agent/ の共有設定とモデルプロファイルをベースに、git 管理しない local 設定を重ねて ~/.pi/agent/ へ配布する。
config/pi-agent/providers.local.json: このマシンで利用可能な provider を availableProviders で指定config/pi-agent/settings.json + model profile + config/pi-agent/settings.local.json → ~/.pi/agent/settings.jsonconfig/pi-agent/models.json + existing target + config/pi-agent/models.local.json → ~/.pi/agent/models.jsonconfig/pi-agent/agents/frontend_worker.md + design profile + config/pi-agent/agents/frontend_worker.local.json → ~/.pi/agent/agents/frontend_worker.md{
"availableProviders": ["opencode-go", "openai-codex"]
}
local 設定は top-level key 単位でマージされ、model profile から enabledModels / defaultProvider / defaultModel / agent ごとの model / fallbackModels / thinking が展開される。
models.json は既存の ~/.pi/agent/models.json を保持しつつ、provider ごとの models を id で upsert する。dry-run では secret を含む可能性がある target 内容は表示しない。
hooks/register.ts 94 lines1// Gives Claude a `compact` tool to compact its own context and keep working.
2// $.session.compact() rejects while a turn runs, so the tool only records the
3// request. The compaction runs once the turn completes, and a prompt carrying
4// `resume` starts the next turn.
5import type { On, SessionCompactArgs, SessionCompactResult } from "claude-code"
6
7const TOOL = "mcp__self-compact__compact"
8
9const DESCRIPTION = [
10 "Compact your own conversation context to free space and keep working.",
11 "The compaction runs right after this turn ends, so end your turn right after calling this tool.",
12 "`resume` is then sent to you as the next prompt: put in it what you need to continue the task.",
13].join(" ")
14
15const INPUT_SCHEMA = {
16 type: "object",
17 properties: {
18 instructions: { type: "string", description: "What the summary must keep or drop" },
19 resume: { type: "string", description: "The prompt to continue with after the compaction" },
20 },
21 required: ["resume"],
22}
23
24type Request = { instructions: string | undefined; resume: string }
25
26type Outcome =
27 | { kind: "compacted" }
28 | { kind: "skipped"; reason: string }
29 | { kind: "failed"; reason: string }
30
31type Compact = (args: Pick<SessionCompactArgs, "instructions">) => Promise<SessionCompactResult>
32
33const isNonEmptyString = (value: unknown): value is string => typeof value === "string" && value.trim() !== ""
34
35// Decides the prompt that starts the next turn from how the compaction ended
36const followUp = (outcome: Outcome, resume: string): string => {
37 switch (outcome.kind) {
38 case "compacted":
39 return resume
40 case "skipped":
41 return `The context was not compacted: ${outcome.reason}\n\n${resume}`
42 case "failed":
43 return `The context compaction failed: ${outcome.reason}\n\n${resume}`
44 }
45}
46
47const compact = async (run: Compact, instructions: string | undefined): Promise<Outcome> => {
48 try {
49 const result = await run(instructions === undefined ? {} : { instructions })
50 return result.skip === undefined ? { kind: "compacted" } : { kind: "skipped", reason: result.skip }
51 } catch (error) {
52 return { kind: "failed", reason: error instanceof Error ? error.message : String(error) }
53 }
54}
55
56// The request recorded by the tool call, consumed when the main loop's turn completes
57let pending: Request | null = null
58
59export function register(on: On) {
60 on("session.start", async ($, e, next) => {
61 await $.tool.register({ name: "compact", description: DESCRIPTION, inputSchema: INPUT_SCHEMA })
62 return next(e)
63 })
64
65 // An MCP-style tool waits behind ToolSearch by default; keep it in the prompt's list
66 on("tool.describe", { tool: TOOL }, async ($, e, next) => ({ ...(await next(e)), isDeferred: false }))
67
68 on("tool.call", { tool: TOOL }, async ($, e) => {
69 // A subagent's context is not the session's, so only the main loop may compact
70 if (e.agentId !== undefined) {
71 return { result: "Not scheduled: only the main conversation can compact the session context." }
72 }
73 if (!isNonEmptyString(e.resume)) {
74 return { result: "Not scheduled: pass `resume`, the prompt to continue with after the compaction." }
75 }
76 pending = { instructions: isNonEmptyString(e.instructions) ? e.instructions : undefined, resume: e.resume }
77 return { result: "Compaction scheduled. End your turn now; `resume` starts the next turn after the compaction." }
78 })
79
80 on("turn.complete", async ($, e, next) => {
81 const result = await next(e)
82 // A subagent's turn also completes here; only the main loop's turn ends the request's turn
83 if (e.agentId === undefined && pending !== null) {
84 const request = pending
85 pending = null
86 // Detached: the compaction cannot start until this turn has finished
87 void compact((args) => $.session.compact(args), request.instructions).then((outcome) =>
88 $.prompt.submit({ text: followUp(outcome, request.resume) }),
89 )
90 }
91 return result
92 })
93}
94