tangled
alpha
login
or
join now
bates64.com
/
infra
0
fork
atom
nixos configs
0
fork
atom
overview
issues
pulls
pipelines
add opencode
bates64.com
1 week ago
024b6ee9
32cd66db
+299
-17
11 changed files
expand all
collapse all
unified
split
.editorconfig
flake.lock
flake.nix
home
alebat01
home.nix
modules
home
ai-agent
default.nix
merge-jsonc.py
opencode
config.arm.jsonc
config.jsonc
oh-my-opencode.arm.jsonc
oh-my-opencode.jsonc
tui.jsonc
+5
.editorconfig
···
1
1
+
root = true
2
2
+
3
3
+
[*.{json,jsonc}]
4
4
+
indent_style = space
5
5
+
indent_size = 2
+94
-13
flake.lock
···
45
45
"type": "github"
46
46
}
47
47
},
48
48
+
"blueprint": {
49
49
+
"inputs": {
50
50
+
"nixpkgs": [
51
51
+
"llm-agents",
52
52
+
"nixpkgs"
53
53
+
],
54
54
+
"systems": "systems_2"
55
55
+
},
56
56
+
"locked": {
57
57
+
"lastModified": 1771437256,
58
58
+
"narHash": "sha256-bLqwib+rtyBRRVBWhMuBXPCL/OThfokA+j6+uH7jDGU=",
59
59
+
"owner": "numtide",
60
60
+
"repo": "blueprint",
61
61
+
"rev": "06ee7190dc2620ea98af9eb225aa9627b68b0e33",
62
62
+
"type": "github"
63
63
+
},
64
64
+
"original": {
65
65
+
"owner": "numtide",
66
66
+
"repo": "blueprint",
67
67
+
"type": "github"
68
68
+
}
69
69
+
},
48
70
"devshell": {
49
71
"inputs": {
50
72
"nixpkgs": [
···
216
238
},
217
239
"flake-utils": {
218
240
"inputs": {
219
219
-
"systems": "systems_5"
241
241
+
"systems": "systems_6"
220
242
},
221
243
"locked": {
222
244
"lastModified": 1731533236,
···
234
256
},
235
257
"flake-utils_2": {
236
258
"inputs": {
237
237
-
"systems": "systems_7"
259
259
+
"systems": "systems_8"
238
260
},
239
261
"locked": {
240
262
"lastModified": 1681202837,
···
340
362
"type": "github"
341
363
}
342
364
},
365
365
+
"llm-agents": {
366
366
+
"inputs": {
367
367
+
"blueprint": "blueprint",
368
368
+
"nixpkgs": [
369
369
+
"nixpkgs"
370
370
+
],
371
371
+
"treefmt-nix": "treefmt-nix_2"
372
372
+
},
373
373
+
"locked": {
374
374
+
"lastModified": 1772634885,
375
375
+
"narHash": "sha256-sizdR/xi8eq12PMPJ3BlGeLZ0lZ38NOra5zgNZVAG1g=",
376
376
+
"owner": "numtide",
377
377
+
"repo": "llm-agents.nix",
378
378
+
"rev": "40dc5f264af66355fb609e3b444dcb8e57f6239f",
379
379
+
"type": "github"
380
380
+
},
381
381
+
"original": {
382
382
+
"owner": "numtide",
383
383
+
"repo": "llm-agents.nix",
384
384
+
"type": "github"
385
385
+
}
386
386
+
},
343
387
"minecraft-plymouth-theme": {
344
388
"inputs": {
345
389
"flake-parts": "flake-parts_2",
346
390
"nixpkgs": "nixpkgs_2",
347
347
-
"systems": "systems_2"
391
391
+
"systems": "systems_3"
348
392
},
349
393
"locked": {
350
394
"lastModified": 1762860197,
···
464
508
"nixpkgs": [
465
509
"nixpkgs"
466
510
],
467
467
-
"systems": "systems_3"
511
511
+
"systems": "systems_4"
468
512
},
469
513
"locked": {
470
514
"lastModified": 1772017571,
···
486
530
"nixpkgs": [
487
531
"nixpkgs"
488
532
],
489
489
-
"systems": "systems_4"
533
533
+
"systems": "systems_5"
490
534
},
491
535
"locked": {
492
536
"lastModified": 1771987719,
···
623
667
"nixpkgs": [
624
668
"nixpkgs"
625
669
],
626
626
-
"systems": "systems_6"
670
670
+
"systems": "systems_7"
627
671
},
628
672
"locked": {
629
673
"lastModified": 1771135771,
···
687
731
"firefox-addons": "firefox-addons",
688
732
"hammerspoon-nix": "hammerspoon-nix",
689
733
"home-manager": "home-manager",
734
734
+
"llm-agents": "llm-agents",
690
735
"minecraft-plymouth-theme": "minecraft-plymouth-theme",
691
736
"minegrub-world-sel-theme": "minegrub-world-sel-theme",
692
737
"niri": "niri",
···
733
778
},
734
779
"systems_3": {
735
780
"locked": {
736
736
-
"lastModified": 1681028828,
737
737
-
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
738
738
-
"owner": "nix-systems",
739
739
-
"repo": "default",
740
740
-
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
781
781
+
"lastModified": 1689347949,
782
782
+
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
783
783
+
"owner": "nix-systems",
784
784
+
"repo": "default-linux",
785
785
+
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
741
786
"type": "github"
742
787
},
743
788
"original": {
744
789
"owner": "nix-systems",
745
745
-
"repo": "default",
790
790
+
"repo": "default-linux",
746
791
"type": "github"
747
792
}
748
793
},
···
776
822
}
777
823
},
778
824
"systems_6": {
825
825
+
"locked": {
826
826
+
"lastModified": 1681028828,
827
827
+
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
828
828
+
"owner": "nix-systems",
829
829
+
"repo": "default",
830
830
+
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
831
831
+
"type": "github"
832
832
+
},
833
833
+
"original": {
834
834
+
"owner": "nix-systems",
835
835
+
"repo": "default",
836
836
+
"type": "github"
837
837
+
}
838
838
+
},
839
839
+
"systems_7": {
779
840
"locked": {
780
841
"lastModified": 1681028828,
781
842
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
···
790
851
"type": "github"
791
852
}
792
853
},
793
793
-
"systems_7": {
854
854
+
"systems_8": {
794
855
"locked": {
795
856
"lastModified": 1681028828,
796
857
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
···
809
870
"inputs": {
810
871
"nixpkgs": [
811
872
"hammerspoon-nix",
873
873
+
"nixpkgs"
874
874
+
]
875
875
+
},
876
876
+
"locked": {
877
877
+
"lastModified": 1770228511,
878
878
+
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
879
879
+
"owner": "numtide",
880
880
+
"repo": "treefmt-nix",
881
881
+
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
882
882
+
"type": "github"
883
883
+
},
884
884
+
"original": {
885
885
+
"owner": "numtide",
886
886
+
"repo": "treefmt-nix",
887
887
+
"type": "github"
888
888
+
}
889
889
+
},
890
890
+
"treefmt-nix_2": {
891
891
+
"inputs": {
892
892
+
"nixpkgs": [
893
893
+
"llm-agents",
812
894
"nixpkgs"
813
895
]
814
896
},
+2
flake.nix
···
3
3
4
4
inputs = {
5
5
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6
6
+
llm-agents.url = "github:numtide/llm-agents.nix";
7
7
+
llm-agents.inputs.nixpkgs.follows = "nixpkgs";
6
8
7
9
minegrub-world-sel-theme.url = "github:Lxtharia/minegrub-world-sel-theme";
8
10
minegrub-world-sel-theme.inputs.nixpkgs.follows = "nixpkgs";
+6
-2
home/alebat01/home.nix
···
1
1
-
{ config, pkgs, ... }:
1
1
+
{
2
2
+
config,
3
3
+
pkgs,
4
4
+
...
5
5
+
}:
2
6
{
3
7
imports = [
4
8
./ssh.nix
···
14
18
templates.commit_trailers = ''if(!trailers.contains_key("Change-Id"), format_gerrit_change_id_trailer(self))'';
15
19
};
16
20
17
17
-
ai-agent.agent = "codex";
21
21
+
ai-agent.agent = "opencode";
18
22
19
23
home.stateVersion = "24.05";
20
24
+37
-2
modules/home/ai-agent/default.nix
···
1
1
{
2
2
lib,
3
3
pkgs,
4
4
+
inputs,
4
5
config,
5
6
...
6
7
}:
7
8
let
9
9
+
llmAgentsPkgs = inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system};
10
10
+
mergeJsonc =
11
11
+
name: base: override:
12
12
+
pkgs.runCommand name { } ''
13
13
+
${
14
14
+
pkgs.python3.withPackages (ps: [ ps.json5 ])
15
15
+
}/bin/python ${./merge-jsonc.py} "${base}" "${override}" "$out"
16
16
+
'';
17
17
+
mergedArmOpencodeConfig =
18
18
+
mergeJsonc "opencode.jsonc" ./opencode/config.jsonc
19
19
+
./opencode/config.arm.jsonc;
20
20
+
mergedArmOhMyOpencodeConfig =
21
21
+
mergeJsonc "oh-my-opencode.jsonc" ./opencode/oh-my-opencode.jsonc
22
22
+
./opencode/oh-my-opencode.arm.jsonc;
8
23
skillsDir =
9
24
{
10
25
"claude-code" = ".claude/skills";
11
26
"codex" = ".codex/skills";
27
27
+
"opencode" = ".opencode/skills";
12
28
}
13
29
.${config.ai-agent.agent};
14
30
···
33
49
type = lib.types.enum [
34
50
"claude-code"
35
51
"codex"
52
52
+
"opencode"
36
53
];
37
54
default = "claude-code";
38
55
description = "Which AI coding agent to install.";
···
41
58
42
59
config = {
43
60
home.packages = [
44
44
-
pkgs.${config.ai-agent.agent}
45
45
-
pkgs.beads
61
61
+
llmAgentsPkgs.${config.ai-agent.agent}
46
62
];
47
63
48
64
home.file.${skillsDir} = {
···
52
68
53
69
home.file.".claude/settings.json" = lib.mkIf (config.ai-agent.agent == "claude-code") {
54
70
text = builtins.toJSON claudeSettings;
71
71
+
};
72
72
+
73
73
+
home.file.".config/opencode/opencode.jsonc" = lib.mkIf (config.ai-agent.agent == "opencode") {
74
74
+
source = lib.mkDefault (
75
75
+
if config.home.username == "alebat01" then mergedArmOpencodeConfig else ./opencode/config.jsonc
76
76
+
);
77
77
+
};
78
78
+
79
79
+
home.file.".config/opencode/tui.jsonc" = lib.mkIf (config.ai-agent.agent == "opencode") {
80
80
+
source = lib.mkDefault ./opencode/tui.jsonc;
81
81
+
};
82
82
+
83
83
+
home.file.".config/opencode/oh-my-opencode.jsonc" = lib.mkIf (config.ai-agent.agent == "opencode") {
84
84
+
source = lib.mkDefault (
85
85
+
if config.home.username == "alebat01" then
86
86
+
mergedArmOhMyOpencodeConfig
87
87
+
else
88
88
+
./opencode/oh-my-opencode.jsonc
89
89
+
);
55
90
};
56
91
};
57
92
}
+45
modules/home/ai-agent/merge-jsonc.py
···
1
1
+
#!/usr/bin/env python3
2
2
+
3
3
+
import json
4
4
+
import sys
5
5
+
6
6
+
import json5
7
7
+
8
8
+
9
9
+
def merge(base_value, override_value):
10
10
+
if isinstance(base_value, dict) and isinstance(override_value, dict):
11
11
+
merged = dict(base_value)
12
12
+
for key, value in override_value.items():
13
13
+
if key in merged:
14
14
+
merged[key] = merge(merged[key], value)
15
15
+
else:
16
16
+
merged[key] = value
17
17
+
return merged
18
18
+
19
19
+
return override_value
20
20
+
21
21
+
22
22
+
def main() -> int:
23
23
+
if len(sys.argv) != 4:
24
24
+
print("Usage: merge-jsonc.py <base.jsonc> <override.jsonc> <out.json>", file=sys.stderr)
25
25
+
return 2
26
26
+
27
27
+
base_path, override_path, out_path = sys.argv[1:4]
28
28
+
29
29
+
with open(base_path, "r", encoding="utf-8") as handle:
30
30
+
base = json5.load(handle)
31
31
+
32
32
+
with open(override_path, "r", encoding="utf-8") as handle:
33
33
+
override = json5.load(handle)
34
34
+
35
35
+
merged = merge(base, override)
36
36
+
37
37
+
with open(out_path, "w", encoding="utf-8") as handle:
38
38
+
json.dump(merged, handle, indent=2)
39
39
+
handle.write("\n")
40
40
+
41
41
+
return 0
42
42
+
43
43
+
44
44
+
if __name__ == "__main__":
45
45
+
raise SystemExit(main())
+32
modules/home/ai-agent/opencode/config.arm.jsonc
···
1
1
+
{
2
2
+
"$schema": "https://opencode.ai/config.json",
3
3
+
"share": "disabled",
4
4
+
"disabled_providers": ["zen", "opencode", "openai"],
5
5
+
"provider": {
6
6
+
"arm": {
7
7
+
"npm": "@ai-sdk/openai",
8
8
+
"name": "Arm",
9
9
+
"options": {
10
10
+
"baseURL": "https://openai-api-proxy.geo.arm.com/api/providers/openai/v1",
11
11
+
},
12
12
+
// Any needed OpenAI model can be added here
13
13
+
"models": {
14
14
+
"gpt-5-mini": {
15
15
+
"id": "gpt-5-mini",
16
16
+
},
17
17
+
"gpt-5.2": {
18
18
+
"id": "gpt-5.2",
19
19
+
},
20
20
+
"gpt-5.2-pro": {
21
21
+
"id": "gpt-5.2-pro",
22
22
+
},
23
23
+
"gpt-5.3-codex": {
24
24
+
"id": "gpt-5.3-codex",
25
25
+
},
26
26
+
"gpt-5.3-codex-spark": {
27
27
+
"id": "gpt-5.3-codex-spark",
28
28
+
},
29
29
+
},
30
30
+
},
31
31
+
},
32
32
+
}
+6
modules/home/ai-agent/opencode/config.jsonc
···
1
1
+
{
2
2
+
"$schema": "https://opencode.ai/config.json",
3
3
+
"plugin": [
4
4
+
"oh-my-opencode", // FIXME: does not install
5
5
+
],
6
6
+
}
+43
modules/home/ai-agent/opencode/oh-my-opencode.arm.jsonc
···
1
1
+
{
2
2
+
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json",
3
3
+
4
4
+
// See https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/refs/heads/dev/docs/guide/agent-model-matching.md
5
5
+
// Work machines use the Arm OpenAI proxy only
6
6
+
// Cost is not a factor, but speed still matters for utility paths
7
7
+
"agents": {
8
8
+
// Sisyphus is Claude-first in upstream docs; use strongest OpenAI general model.
9
9
+
"sisyphus": {
10
10
+
"model": "arm/gpt-5.2-pro",
11
11
+
"ultrawork": { "model": "arm/gpt-5.3-codex", "variant": "xhigh" },
12
12
+
},
13
13
+
14
14
+
// Utility/search agents: use faster model for snappier turnaround.
15
15
+
"librarian": { "model": "arm/gpt-5-mini" },
16
16
+
"explore": { "model": "arm/gpt-5-mini" },
17
17
+
18
18
+
// Deep/specialist agents.
19
19
+
"hephaestus": { "model": "arm/gpt-5.3-codex", "variant": "xhigh" },
20
20
+
"oracle": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" },
21
21
+
"momus": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" },
22
22
+
"metis": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" },
23
23
+
"atlas": { "model": "arm/gpt-5.2" },
24
24
+
25
25
+
// Keep the same orchestration bias tweak.
26
26
+
"prometheus": {
27
27
+
"prompt_append": "Leverage deep & quick agents heavily, always in parallel.",
28
28
+
},
29
29
+
},
30
30
+
31
31
+
"categories": {
32
32
+
"quick": { "model": "arm/gpt-5-mini" },
33
33
+
"unspecified-low": { "model": "arm/gpt-5-mini" },
34
34
+
"unspecified-high": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" },
35
35
+
"writing": { "model": "arm/gpt-5.2-pro" },
36
36
+
"visual-engineering": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" },
37
37
+
38
38
+
// Additional upstream-style categories mapped to OpenAI-only models.
39
39
+
"deep": { "model": "arm/gpt-5.3-codex", "variant": "xhigh" },
40
40
+
"ultrabrain": { "model": "arm/gpt-5.3-codex", "variant": "xhigh" },
41
41
+
"artistry": { "model": "arm/gpt-5.2-pro", "variant": "xhigh" },
42
42
+
},
43
43
+
}
+13
modules/home/ai-agent/opencode/oh-my-opencode.jsonc
···
1
1
+
{
2
2
+
"$schema": "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/dev/assets/oh-my-opencode.schema.json",
3
3
+
"experimental": {
4
4
+
"aggressive_truncation": true,
5
5
+
"task_system": true,
6
6
+
"dynamic_context_pruning": {
7
7
+
"enabled": true,
8
8
+
"notification": "minimal",
9
9
+
},
10
10
+
},
11
11
+
"tmux": { "enabled": false },
12
12
+
"hashline_edit": true,
13
13
+
}
+16
modules/home/ai-agent/opencode/tui.jsonc
···
1
1
+
{
2
2
+
"$schema": "https://opencode.ai/tui.json",
3
3
+
4
4
+
"theme": "system",
5
5
+
6
6
+
//"scroll_speed": 1, // Anything higher is impossible to use with a touchpad
7
7
+
"scroll_acceleration": {
8
8
+
"enabled": true,
9
9
+
},
10
10
+
11
11
+
"keybinds": {
12
12
+
"agent_cycle_reverse": "none",
13
13
+
"model_cycle_favorite": "shift+tab",
14
14
+
"tool_details": "none",
15
15
+
},
16
16
+
}