Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion conf/llm/docs/coding-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
- **Reuse:** Prefer existing utilities/components via explicit interfaces—do not break abstraction boundaries.
- **Precedent:** Follow prior implementations for new features unless told otherwise.
- **Structured Plan:** For each step, specify target files and exact required changes.
- **Boundaries:** Keep business logic isolated from UI. Place demo/mock code at the top layer. Don't modify production code just for debugging.
- **Boundaries:** Keep business logic isolated from UI. Place demo/mock code at the top layer. Don't modify production code just for debugging.
- **Separation of concerns:** Bad: Use other layer's implement details in current layer that current layer should not know or care about. Good: current layer use it's own knowledge based implement details, dependant layers can depends on that to derive implement details.
- **Abstraction:** Only use explicitly exposed abstractions from the immediate downstream layer—avoid private APIs, even for reuse.
- **Fail Fast:** Let bugs surface; do not mask errors with `try-catch` or optional chaining.
- **Comment Intent:** Use `FIXME`, `TODO`, and `NOTE` to flag issues, explain logic, document changes, and note trade-offs.
Expand Down
14 changes: 11 additions & 3 deletions nix/hm/ai/claude/hooks/session_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def generate_summary(messages: list, cwd: str) -> str:
return ""


def save_summary(cwd: str, summary: str, timestamp: str, session_id: str):
def save_summary(cwd: str, summary: str, timestamp: str, session_id: str, session_file: str = ""):
"""Save summary to session-summary directory with session ID.

NOTE: This function is paired with `session_summary.py` which reads these files
Expand All @@ -241,6 +241,7 @@ def save_summary(cwd: str, summary: str, timestamp: str, session_id: str):
summary: Summary text
timestamp: Timestamp string (YYYYMMDD-HHMMSS)
session_id: Session ID
session_file: Path to the full session file (relative to cwd)
"""
if not summary or not session_id:
return
Expand All @@ -257,10 +258,15 @@ def save_summary(cwd: str, summary: str, timestamp: str, session_id: str):
# Use existing file or create new one with timestamp
summary_file = existing_file or summary_dir / f"{timestamp}-summary-ID_{session_id}.md"

# Append session file reference if available
content = summary
if session_file:
content = f"{summary}\n\nFull session: {session_file}"

try:
# Always overwrite summary (update, don't append)
with open(summary_file, "w") as f:
f.write(summary)
f.write(content)
os.chmod(summary_file, 0o600)
print(f"✓ Summary saved to {summary_file.name}", file=sys.stderr)
except Exception as e:
Expand Down Expand Up @@ -322,7 +328,9 @@ def save_session(cwd: str, messages: list, session_id: str, reason: str = ""):
# Generate and save summary for next session (only on "clear" reason)
if reason == "clear":
summary = generate_summary(messages, cwd)
save_summary(cwd, summary, timestamp, session_id)
# Pass relative session file path
session_file_rel = str(filepath.relative_to(cwd)) if filepath else ""
save_summary(cwd, summary, timestamp, session_id, session_file_rel)
elif reason:
print(f"⊘ Summary skipped (reason='{reason}', need 'clear')", file=sys.stderr)

Expand Down
6 changes: 3 additions & 3 deletions nix/hm/ai/claude/hooks/session_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ def main():
sys.exit(0)

# Return as additional context for new session
context = f"""## Previous Session Context
context = f"""<history-summary>

{summary}"""
{summary}</history-summary>"""

# Create a visible system message
system_msg = f"📝 Previous session: {summary}"
system_msg = f"History context loaded"

output = {
"systemMessage": system_msg,
Expand Down
5 changes: 1 addition & 4 deletions nix/hm/ai/claude/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
"WebFetch",
"WebSearch",
"Read(./.env)",
"Read(/dev/**)",
"Read(./.env.*)",
"Read(.private.*)",
"Read(./secrets/**)",
Expand Down Expand Up @@ -205,10 +206,6 @@
{
"type": "command",
"command": "uv run ~/.dotfiles/nix/hm/ai/claude/hooks/session_summary.py"
},
{
"type": "command",
"command": "uv run ~/.dotfiles/nix/hm/ai/claude/hooks/session_start_handoff.py"
}
]
}
Expand Down
95 changes: 48 additions & 47 deletions nix/hm/ai/codex/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
}:
let
proxyConfig = import ../../../lib/proxy.nix { inherit lib pkgs; };
mcp = import ../../../modules/ai/mcp.nix { inherit pkgs lib config; };
codex_home = "${config.xdg.configHome}/codex";
codexMcpToml = builtins.readFile (
(pkgs.formats.toml { }).generate "codex-mcp.toml" { mcp_servers = mcp.clients.codex; }
);
# codex_config_file = "${codex_home}/config.toml";
# like commands in other agents
# prompts_dir = "${codex_home}/prompts";
Expand All @@ -30,15 +34,34 @@ in
source = ./instructions;
recursive = true;
};
"codex/skills" = {
source = ../../../../conf/claude-local-marketplace/skills;
recursive = true;
};
# toml
"codex/config.toml".text = ''
model = "gpt-5"
model_provider = "litellm"
"codex/config-generated.toml".text = ''
model = "gpt-5.2-medium"
model_provider = "packy"
approval_policy = "untrusted"
model_reasoning_effort = "low"
model_reasoning_effort = "medium"
# the AGENTS.md contains instructions for using codex mcp, do not use it
# experimental_instructions_file = "${config.xdg.configHome}/AGENTS.md"
sandbox_mode = "read-only"
project_doc_fallback_filenames = ["CLAUDE.md"]
sandbox_mode = "workspace-write"

[features]
tui2 = true
skills = true
unified_exec = true
apply_patch_freeform = true
view_image_tool = false
ghost_commit = false

[model_providers.packy]
name = "packy"
wire_api = "responses"
base_url = "https://www.packyapi.com/v1"
env_key = "PACKYCODE_CODEX_API_KEY"

[model_providers.litellm]
name = "litellm"
Expand Down Expand Up @@ -104,31 +127,17 @@ in
hide_agent_reasoning = true
model_verbosity = "low"

[profiles.sage_slow]
model = "glm-4.6"
model_provider = "zhipuai-coding-plan"
sandbox_mode = "read-only"
experimental_instructions_file = "${codex_home}/instructions/sage-role.md"
approval_policy = "never"
model_reasoning_effort = "medium"
model_reasoning_summary = "concise"
hide_agent_reasoning = true
model_verbosity = "low"

[profiles.sage]
model = "kimi-k2-turbo-preview"
model_provider = "moonshot"
sandbox_mode = "read-only"
experimental_instructions_file = "${codex_home}/instructions/sage-role.md"
approval_policy = "never"
model_reasoning_effort = "low"
model_reasoning_summary = "concise"
hide_agent_reasoning = true
model_verbosity = "medium"

[tui]
# notifications = [ "agent-turn-complete", "approval-requested" ]
notifications = true
animations = false
scroll_events_per_tick = 3
scroll_wheel_lines = 3
scroll_mode = "auto"

[sandbox_workspace_write]
network_access = true
writable_roots = ["${config.home.homeDirectory}/workspace/work"]

[shell_environment_policy]
inherit = "core"
Expand All @@ -140,26 +149,18 @@ in
set = { HTTP_PROXY = "${proxyConfig.proxies.http}", HTTPS_PROXY = "${proxyConfig.proxies.https}" }

## MCP
[mcp_servers.chromedev]
command = "bunx"
args = ["chrome-devtools-mcp@latest", "--browser-url=http://127.0.0.1:9222"]

# [mcp_servers.context7]
# command = "bunx"
# args = ["@upstash/context7-mcp"]

# [mcp_servers.mermaid]
# command = "bunx"
# args = ["@devstefancho/mermaid-mcp"]

# [mcp_servers.sequentialthinking]
# command = "bunx"
# args = ["@modelcontextprotocol/server-sequential-thinking"]

# [mcp_servers.github]
# command = "github-mcp-server"
# args = ["stdio", "--dynamic-toolsets"]
# env = { GITHUB_PERSONAL_ACCESS_TOKEN = "${pkgs.nix-priv.keys.github.accessToken}" }
${codexMcpToml}
'';
};

home.activation = {
setupCodexConfig = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
CODEX_HOME="${codex_home}"

cp -f ${codex_home}/config-generated.toml "${codex_home}/config.toml"
chmod u+w "${codex_home}/config.toml"

cat ${../../../../conf/llm/docs/coding-rules.md} > ${codex_home}/AGENTS.md
'';
};
}
36 changes: 0 additions & 36 deletions nix/hm/ai/codex/instructions/sage-role.md

This file was deleted.

2 changes: 1 addition & 1 deletion nix/hm/ai/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
./legacy.nix
./claude
./codex
./forge
# ./forge
# ./windsurf
# ./cline
./droid
Expand Down
61 changes: 61 additions & 0 deletions nix/lib/mcp-clients.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,67 @@
...
}:
{
# codex (openai/codex) config format:
# - STDIO servers: { command, args?, env?, env_vars?, cwd?, ... }
# - Streamable HTTP servers: { url, bearer_token_env_var?, http_headers?, env_http_headers?, ... }
codex =
serverAttrs:
let
passthru =
lib.optionalAttrs (serverAttrs ? enabled) { inherit (serverAttrs) enabled; }
// lib.optionalAttrs (serverAttrs ? startup_timeout_sec) {
inherit (serverAttrs) startup_timeout_sec;
}
// lib.optionalAttrs (serverAttrs ? tool_timeout_sec) {
inherit (serverAttrs) tool_timeout_sec;
}
// lib.optionalAttrs (serverAttrs ? enabled_tools) { inherit (serverAttrs) enabled_tools; }
// lib.optionalAttrs (serverAttrs ? disabled_tools) { inherit (serverAttrs) disabled_tools; }
// lib.optionalAttrs (serverAttrs ? cwd) { inherit (serverAttrs) cwd; };

mkStdio =
base:
base
// lib.optionalAttrs (serverAttrs ? environment && serverAttrs.environment != { }) {
env = serverAttrs.environment;
}
// lib.optionalAttrs (serverAttrs ? env_vars && serverAttrs.env_vars != [ ]) {
inherit (serverAttrs) env_vars;
}
// passthru;
in
if serverAttrs.type == "local" then
mkStdio {
inherit (serverAttrs) command;
args = serverAttrs.args or [ ];
}
else if serverAttrs.type == "sse" then
mkStdio {
command = "bunx";
args = [
"mcp-remote"
serverAttrs.url
"--allow-http"
"--header"
"Authorization: ${serverAttrs.headers.Authorization}"
];
}
else
{
inherit (serverAttrs) url;
}
// lib.optionalAttrs (serverAttrs ? bearer_token_env_var) {
inherit (serverAttrs) bearer_token_env_var;
}
// lib.optionalAttrs (serverAttrs ? http_headers) { inherit (serverAttrs) http_headers; }
// lib.optionalAttrs (serverAttrs ? env_http_headers) {
inherit (serverAttrs) env_http_headers;
}
// lib.optionalAttrs (serverAttrs ? headers && serverAttrs.headers != { }) {
http_headers = serverAttrs.headers;
}
// passthru;

opencode =
let
typeMap = {
Expand Down
10 changes: 10 additions & 0 deletions nix/modules/ai/mcp.nix
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,16 @@ rec {
};

clients = {
codex = mapWithClientMk clientMk.codex (
pick mcpServers [
"chromedev"
"context7"
"mermaid"
"github"
"exa"
"mastergo"
]
);
opencode = mapWithClientMk clientMk.opencode (
pick mcpServers [
"kg"
Expand Down
Loading