Compare commits

..
Author SHA1 Message Date
m3tam3re 30c753f4ca chore: updates 2026-07-25 11:44:00 +02:00
m3tam3re d932db10c4 chore: some updates 2026-07-16 17:05:41 +02:00
m3tam3re 01bede8826 fix: add n8n xlsx lockfile integrity workaround 2026-07-10 13:22:27 +02:00
m3tam3re 5dc91eeebb fix: update n8n overlay to 2.29.8 2026-07-10 12:42:04 +02:00
m3tam3re f279ae9c89 fix: n8n overlay 2026-07-05 18:41:05 +02:00
m3tam3re 94af31806a Merge pull request 'refactor: split n8n overlay override' (#26) from feat/n8n-overlay-override into master
Reviewed-on: #26
2026-07-04 09:32:57 +02:00
m3tam3re eedac010ca refactor: split n8n overlay override 2026-07-04 09:30:16 +02:00
m3tam3re c767d792af Merge pull request 'refactor: replace n8n package with overlay override' (#25) from feat/n8n-overlay-override into master
Reviewed-on: #25
2026-07-04 09:22:11 +02:00
m3tam3re 670c6e54d7 refactor: replace n8n package with overlay override 2026-07-04 09:16:30 +02:00
m3tam3re 399cec6283 chore: n8n update 2026-07-03 12:54:10 +02:00
m3tam3re fc5092d72d Merge pull request 'feat(talk): read API key from agenix file' (#24) from feat/talk-agenix-key into master
Reviewed-on: #24
2026-07-02 20:15:29 +02:00
m3ta-chiron e7765ee39f feat(talk): read API key from agenix file instead of env var
Primary: /run/agenix/elevenlabs-key (read via 'read -r' which strips
the trailing newline agenix files contain).
Fallback: ELEVENLABS_API_KEY env var (backwards compatible).

No need to export the key in shell environment anymore — if the
agenix secret exists, talk picks it up automatically.

Override path via ELEVENLABS_KEY_FILE env var if needed.
2026-07-02 20:14:45 +02:00
m3tam3re 3d6b3160b2 Merge pull request 'docs: add README for talk and crunch packages' (#23) from docs/talk-crunch-readmes into master
Reviewed-on: #23
2026-07-02 20:09:40 +02:00
m3ta-chiron 75b88553c6 docs: add README for talk and crunch packages
Each README covers usage, environment variables, integration patterns,
NixOS installation, and how-it-works diagrams.
2026-07-02 20:00:58 +02:00
m3tam3re 0341a1348e Merge pull request 'feat(crunch): add script mode for custom pipeline jobs' (#22) from feat/crunch-script-mode into master
Reviewed-on: #22
2026-07-02 19:56:48 +02:00
m3ta-chiron 8b3d762bc9 feat(crunch): add script mode for custom pipeline jobs
crunch script <type> <time> <script.sh> [args...]

Runs any shell script on schedule. Script stdout is piped to talk
for voice output. Empty stdout = silence (no error thrown).

Enables complex multi-step pipelines:
  - Fetch data (basecamp, gh, curl)
  - Write reports to disk
  - Pipe through pi/opencode for AI summarization
  - Final stdout → talk voice notification

Example:
  crunch script daily '08:00' ~/scripts/basecamp-daily.sh
2026-07-02 19:55:31 +02:00
m3tam3re 9e96e92cfe Merge pull request 'fix(talk): cancel button now stops audio playback' (#21) from fix/talk-cancel-button into master
Reviewed-on: #21
2026-07-02 19:44:48 +02:00
m3ta-chiron c94ff86c12 fix(talk): cancel button now stops audio playback
The shell '>' redirect creates ACTION_FILE immediately as an empty file.
The poll loop checked [ -f ] (exists) instead of [ -s ] (non-empty),
so it matched on the first 0.2s iteration, found no 'cancel' string,
and broke out of the loop — leaving mpv running with no listener.

[ -s ] only returns true once notify-send writes 'cancel' to the file
(i.e. when the user actually clicks the Abbrechen action).
2026-07-02 19:43:53 +02:00
m3tam3re 02911c40ca Merge pull request 'feat(crunch): voice-notified reminders and AI crunch jobs' (#20) from feat/crunch-package into master
Reviewed-on: #20
2026-07-02 19:39:39 +02:00
m3ta-chiron 8c9ed72857 feat(crunch): voice-notified reminders and AI crunch jobs via systemd timers
crunch schedules transient systemd --user timers that fire talk (TTS)
or AI agents (pi/opencode) → talk at specified times.

Commands:
  crunch at <time> <message>           One-shot
  crunch in <duration> <message>       One-shot after delay
  crunch daily <time> <message>        Recurring daily
  crunch weekly <day> <time> <message> Recurring weekly
  crunch ai <engine> <type> <time> <prompt>  AI crunch
  crunch list                          List jobs
  crunch cancel <name>                 Cancel job
  crunch purge                         Clean fired jobs

Supports German and English day names (Montag→Mon, etc).
2026-07-02 19:36:24 +02:00
m3tam3re f471f908ba Merge pull request 'talk: chiron.jpeg notification icon' (#19) from feat/talk-chiron-icon into master
Reviewed-on: #19
2026-07-02 19:26:03 +02:00
m3ta-chiron 09098d902b talk: use chiron.jpeg as notification icon
Replace generic audio-x-generic icon with chiron.jpeg fetched from S3
into the nix store at build time.
2026-07-02 19:25:36 +02:00
m3tam3re 0306624074 Merge pull request 'feat(talk): ElevenLabs TTS voice notification package' (#18) from feat/talk-package into master
Reviewed-on: #18
2026-07-02 19:11:23 +02:00
m3ta-chiron fa2f3dfbc6 feat(talk): support stdin piping
Argument has priority, otherwise read from stdin when piped.
Enables: echo 'Build fertig' | talk
         nixos-rebuild build 2>&1 | tail -3 | talk
2026-07-02 19:09:52 +02:00
m3tam3re 0aa34ae368 Merge pull request 'feat(talk): ElevenLabs TTS voice notification package' (#17) from feat/talk-package into master
Reviewed-on: #17
2026-07-02 18:53:06 +02:00
m3ta-chiron b7ba13db9b feat(talk): add ElevenLabs TTS voice notification package
- writeShellScriptBin with mpv audio + notify-send cancel button
- Simultaneous audio playback and notification popup
- VOICE_NOTIFY=0 toggle for disabling
- Uses eleven_multilingual_v2 model with configurable voice ID
- Cruncher job wrapper for task completion notifications
2026-07-02 18:51:31 +02:00
m3ta-chiron abd910d667 chore: update n8n + vibetyper 2026-07-01 18:51:40 +02:00
Sascha König e695a8c636 chore: update agent sources 2026-06-30 08:17:29 +02:00
m3tam3re d42a6f57f5 chore: some updates 2026-06-27 08:28:12 +02:00
m3tam3re f0c028a62c chore n8n update 2026-06-25 07:09:59 +02:00
m3tam3re b50dcf843b fix: vibetyper window rules 2026-06-20 10:56:01 +02:00
m3tam3re 96f5d7f378 chore: update n8n, openwork, vibetyper 2026-06-19 14:32:38 +02:00
m3ta-chiron 5aa54c6e34 chore: vibetyper update 2026-06-16 19:26:47 +02:00
Sascha König 050c273c65 openwork: init at 0.16.4 2026-06-15 07:11:19 +02:00
Sascha König aa0108936c kestractl: 1.4.0 -> 1.15.0 2026-06-15 07:00:23 +02:00
Sascha König 2017d27733 openshell: 0.0.23 -> 0.0.62 2026-06-15 07:00:07 +02:00
m3tam3re 8fae0726a5 chore: updates 2026-06-11 06:59:30 +02:00
m3tam3re ae1fb97c21 chore: n8n update 2026-05-28 06:53:57 +02:00
m3tam3re 20678635f8 chore: app updates 2026-05-23 08:31:36 +02:00
m3tam3re e38971e68d feat(editors): migrate Zed config from JSON settings
- Add CLI behavior and agent UI font size settings
- Merge duplicated agent block with dock/default_profile/version
- Keep Anthropic default model (claude-4) from current active block
- Add agent_servers registry configuration for pi-acp
- Add rust_analyzer binary path_lookup setting
- Add panel layout (project, outline, collaboration, git docks to left)
- Remove placeholder context_server (example only)
- Add SSH connections for m3-atlas, self-host-playbook, m3-daedalus
- Update features with copilot=false and inline_prediction_provider
- Preserve edit_predictions provider setting
- Add default_profile=ask for agent
2026-05-23 08:11:10 +02:00
m3tam3re 688ddf4e21 kestractl: 1.3.0 -> 1.4.0 2026-05-23 07:47:51 +02:00
nix-update bot dde103e31e chore: update flake inputs 2026-05-22 16:01:07 +02:00
nix-update bot 0bf0bde93b chore: update flake inputs 2026-05-22 04:01:04 +02:00
nix-update bot 8b978d8e29 chore: update flake inputs 2026-05-21 16:01:41 +02:00
nix-update bot 907daddcd1 chore: update flake inputs 2026-05-21 04:01:22 +02:00
m3ta-chiron 50a182b259 chore: n8n update 2026-05-20 19:57:15 +02:00
nix-update bot 2eeafdef65 chore: update flake inputs 2026-05-20 16:01:49 +02:00
nix-update bot 5a0629ca43 eigent: 0.0.90 -> 0.0.91
Diff: https://github.com/eigent-ai/eigent/compare/v0.0.90...v0.0.91
2026-05-20 04:02:19 +02:00
nix-update bot b4bf3fc5b8 chore: update flake inputs 2026-05-20 04:01:29 +02:00
nix-update bot ac3418a667 chore: update flake inputs 2026-05-19 16:01:41 +02:00
nix-update bot 8a24c06018 chore: update flake inputs 2026-05-19 04:01:18 +02:00
nix-update bot f265aaff10 chore: update flake inputs 2026-05-18 16:01:31 +02:00
Sascha König b4efb556cf chore: update n8n 2026-05-18 07:12:01 +02:00
nix-update bot ce6c93add9 chore: update flake inputs 2026-05-17 16:01:20 +02:00
nix-update bot ab268c5191 chore: update flake inputs 2026-05-17 04:01:30 +02:00
nix-update bot ea2e84c4ab chore: update flake inputs 2026-05-16 16:02:09 +02:00
nix-update bot 33d3d3d56e chore: update flake inputs 2026-05-16 04:01:25 +02:00
nix-update bot 23a26bbbb3 chore: update flake inputs 2026-05-15 16:01:17 +02:00
nix-update bot af3b1abaae chore: update flake inputs 2026-05-15 04:01:29 +02:00
nix-update bot ef820b0e4a chore: update flake inputs 2026-05-14 16:01:44 +02:00
nix-update bot 4f939d96ba chore: update flake inputs 2026-05-14 04:01:17 +02:00
nix-update bot 6ef39d82b3 chore: update flake inputs 2026-05-13 16:01:15 +02:00
nix-update bot 15ea83833d chore: update flake inputs 2026-05-13 04:01:07 +02:00
nix-update bot 9859da6e62 chore: update flake inputs 2026-05-12 16:00:45 +02:00
nix-update bot a38ee223e6 chore: update flake inputs 2026-05-12 04:00:41 +02:00
m3tam3re d64c581516 refactor: mkOpencodeSkills -> mkSkills 2026-05-11 18:59:49 +02:00
nix-update bot 8113723a48 chore: update flake inputs 2026-05-11 16:00:52 +02:00
nix-update bot 14fd00426c chore: update flake inputs 2026-05-11 04:00:39 +02:00
nix-update bot 3d2979dba2 chore: update flake inputs 2026-05-10 16:01:07 +02:00
nix-update bot 8f1682a666 chore: update flake inputs 2026-05-10 04:00:35 +02:00
nix-update bot 0208efb928 chore: update flake inputs 2026-05-09 16:00:47 +02:00
m3tm3re db1a29df15 chore: upates for vibetyper + n8n 2026-05-09 08:52:46 +02:00
nix-update bot ef4b07a896 chore: update flake inputs 2026-05-09 04:01:02 +02:00
nix-update bot 5a19f4096d chore: update flake inputs 2026-05-08 16:00:43 +02:00
nix-update bot 03944ac550 mem0: 2.0.1 -> 2.0.2
Diff: https://github.com/mem0ai/mem0/compare/v2.0.1...v2.0.2

Changelog: https://github.com/mem0ai/mem0/releases/tag/v2.0.2
2026-05-08 04:01:35 +02:00
nix-update bot 60eece2899 chore: update flake inputs 2026-05-08 04:00:45 +02:00
m3ta-chiron 8d7a1b4f3d chore: n8n update 2026-05-07 19:30:57 +02:00
nix-update bot 6156228233 chore: update flake inputs 2026-05-07 16:00:49 +02:00
nix-update bot 4965c9e73f chore: update flake inputs 2026-05-07 04:01:07 +02:00
nix-update bot 676064484f chore: update flake inputs 2026-05-06 16:01:12 +02:00
nix-update bot db71e3adb1 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 4m5s
2026-05-06 04:01:22 +02:00
nix-update bot 5a4581db07 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 4m11s
2026-05-05 16:01:33 +02:00
nix-update bot 8883c8d7ab chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 5m9s
2026-05-05 04:01:09 +02:00
nix-update bot 98424b0f3d chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 3m46s
2026-05-04 16:01:14 +02:00
nix-update bot 5587703b77 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m52s
2026-05-04 04:01:28 +02:00
nix-update bot fad0892182 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 33m55s
2026-05-03 16:01:13 +02:00
nix-update bot 1ffa8bc203 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m43s
2026-05-03 04:01:13 +02:00
nix-update bot eda51a9e89 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m42s
2026-05-02 16:01:53 +02:00
nix-update bot fa28774656 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 5m22s
2026-05-02 04:01:15 +02:00
nix-update bot c6c3ffb548 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 3m53s
2026-05-01 16:01:13 +02:00
nix-update bot 9b423315b3 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m42s
2026-05-01 04:01:14 +02:00
nix-update bot 14d906ef93 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m36s
2026-04-30 16:01:17 +02:00
nix-update bot e7393d6fa4 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 4m6s
2026-04-30 04:00:54 +02:00
m3ta-chiron 1da8c96447 fix(pi): correct guardrails enable option string
Update Nix Packages with nix-update / nix-update (push) Failing after 34m23s
2026-04-29 20:07:12 +02:00
m3ta-chiron 6a8cb62903 style(pi): format guardrails module with alejandra 2026-04-29 19:51:35 +02:00
m3ta-chiron a3e247e5af feat(pi): add guardrails config option for pi-guardrails integration
Adds a guardrails submodule option to coding.agents.pi that:
- Generates ~/.pi/agent/extensions/guardrails.json when enabled
- Automatically injects @aliou/pi-guardrails package into settings.packages
- Provides structured options for policies, pathAccess, and permissionGate

The module generates the JSON config that pi-guardrails reads for
its security hooks (policies, permission-gate, path-access).

Limitations documented in option descriptions:
- Path access checks are lexical (not symlink-safe)
- Local project guardrails.json can override global rule IDs
2026-04-29 19:48:10 +02:00
m3ta-chironandm3tm3re f7f0c4072e fix(n8n): use stable tag target to get actual version
The previous jq filter grabbed the first non-stable release by creation date,
which incorrectly returned 1.123.38 instead of the latest stable 2.18.5.

Now query the 'stable' tag directly and extract version from its
target_commitish (e.g., 'release/2.18.5' -> '2.18.5'), ensuring we always
get the actual latest stable version.

Also bump version from 2.17.8 to 2.18.5 with updated hashes.
2026-04-29 18:40:49 +02:00
m3tm3re e601fde026 kestractl: 1.2.2 -> 1.3.0 2026-04-29 18:39:03 +02:00
nix-update bot 642e764b81 chore: update flake inputs 2026-04-29 16:01:26 +02:00
nix-update bot 0a224db2fc chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m39s
2026-04-29 04:01:44 +02:00
nix-update bot 69e8fb93be chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 23m34s
2026-04-28 16:01:26 +02:00
nix-update bot c63ecc899c td: 0.43.0 -> 0.44.0
Update Nix Packages with nix-update / nix-update (push) Successful in 2m35s
Diff: https://github.com/marcus/td/compare/v0.43.0...v0.44.0
2026-04-28 04:03:27 +02:00
nix-update bot 5d2bfbd27c sidecar: 0.83.0 -> 0.84.0
Diff: https://github.com/marcus/sidecar/compare/v0.83.0...v0.84.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.84.0
2026-04-28 04:02:57 +02:00
nix-update bot 66c398d196 mem0: 1.0.9 -> 2.0.1
Diff: https://github.com/mem0ai/mem0/compare/v1.0.9...v2.0.1

Changelog: https://github.com/mem0ai/mem0/releases/tag/v2.0.1
2026-04-28 04:02:08 +02:00
nix-update bot 729ea971c5 chore: update flake inputs 2026-04-28 04:01:09 +02:00
m3tm3re ce16dfff2e chore(beads): initialize issue tracker
Update Nix Packages with nix-update / nix-update (push) Failing after 37m14s
Add nixpkgs-ng1 task: Configure agent git identity
2026-04-27 20:16:27 +02:00
m3tm3re 31464e245e chore(nix): remove deprecated packages
- Remove opencode flake input (old v1.4.3 URL, superseded)
- Remove code2prompt package
- Remove opencode-desktop package
2026-04-27 20:14:18 +02:00
m3ta-chiron 251a6892a3 fix(n8n): resolve nix-update hash prefetch failure
- Remove --pure from nix-shell shebang to allow network access
- Add --flake --system x86_64-linux for proper flake evaluation
- Navigate to nixpkgs root before running nix-update
- Also bump version 2.17.5 -> 2.17.8
2026-04-27 19:46:14 +02:00
m3tam3re 95aeff28ad Merge pull request 'feature/agent-git-identity' (#16) from feature/agent-git-identity into master
Reviewed-on: #16
2026-04-27 17:56:26 +02:00
m3tm3re fa339ae8cc fix(agents): correct shared-options.nix import paths from ../ to ./ 2026-04-27 13:17:11 +02:00
m3tm3re cec0c31d91 fix(agents): correct shared-options.nix import path 2026-04-27 13:11:11 +02:00
m3tm3re 6a8360305d fix(agents): remove shared-options.nix from imports to avoid module system conflict 2026-04-27 13:08:40 +02:00
m3tm3re 5edd0929d0 fix(agents): correct import paths for shared module 2026-04-27 13:00:52 +02:00
m3tm3re 60aeec7cfe feat(agents): add gitIdentity module
- Renamed shared-options.nix to shared/shared-options.nix
- Created shared/default.nix importing git-identity.nix and shared-options.nix
- Created shared/git-identity.nix with gitIdentity option set:
  - enable: Toggle for agent git identity
  - name: Git author name (default: m3ta-chiron)
  - email: Git author email (default: m3ta-chiron@agentmail.to)
  - signingKey: Optional GPG signing key path
  - sshKey: SSH private key path for git push auth
- Updated opencode.nix, pi.nix, claude-code.nix to import shared/default.nix
- Restructured modules to follow proper Nix module syntax with imports at top level
2026-04-27 12:43:56 +02:00
m3tm3re 161be34111 chore: beads init
Update Nix Packages with nix-update / nix-update (push) Failing after 3h23m59s
2026-04-26 14:06:57 +02:00
m3tm3re 7b6bcfeb1c fix: force overwrite for pi mcp.json and settings.json 2026-04-26 13:25:12 +02:00
m3tm3re 03ad7451fc feat: update documentation, lib functions, modules, and packages
Update Nix Packages with nix-update / nix-update (push) Failing after 3h23m59s
2026-04-22 18:50:31 +02:00
sascha.koenig 69b736e302 chore: update flake, agents lib, and clean up tracked dotfiles
Update Nix Packages with nix-update / nix-update (push) Failing after 3m59s
- Remove .pi* and .td-root files from git index (now in .gitignore)
- Update flake.lock and flake.nix
- Add shells/coding.nix, remove shells/opencode.nix
- Update lib/agents.nix, lib/coding-rules.nix
- Update modules/home-manager/coding/agents/pi.nix
- Update tests for agents and coding-rules
- Update .gitignore
2026-04-21 20:24:38 +02:00
m3tam3re 300ef0c28f Merge pull request 'refactor/remove-legacy-mkopencoderules' (#15) from refactor/remove-legacy-mkopencoderules into master
Update Nix Packages with nix-update / nix-update (push) Failing after 8m3s
Reviewed-on: #15
2026-04-20 19:20:49 +02:00
sascha.koenig 57ebad1358 refactor: remove legacy mkOpencodeRules alias and opencode-rules compat entry
- Remove mkOpencodeRules backward-compat alias from lib/coding-rules.nix
- Remove opencode-rules alias from lib/default.nix
- Update shells/opencode.nix to use mkCodingRules / coding-rules
- Remove backward-compat test from tests/lib/coding-rules-test.nix
- Update AGENTS.md and modules/home-manager/AGENTS.md docs
- Apply nix fmt formatting to shared-options.nix
2026-04-20 19:16:22 +02:00
sascha.koenig 35f4821bc5 refactor: centralize agent skills at ~/.agents/skills 2026-04-20 08:58:15 +02:00
m3tam3re bc41c9a428 Merge pull request 'refactor/remove-pi-agent-cleanup' (#14) from refactor/remove-pi-agent-cleanup into master
Update Nix Packages with nix-update / nix-update (push) Failing after 4m2s
Reviewed-on: #14
2026-04-19 18:16:50 +02:00
m3tm3re edae9ba3c9 chore: update n8n, vibetyper 2026-04-19 18:11:43 +02:00
Chiron 54fa93574b refactor: remove dead code, extract shared agent options, optimize flake
- Remove dead overlays/default.nix (flake defines overlays inline)
- Remove orphaned overlays/mods/{beads,n8n}.nix (never imported)
- Remove docs/packages/notesmd-cli.md (package doesn't exist)
- Extract externalSkills submodule to shared-options.nix (eliminates
  ~100 lines of duplication across opencode/claude-code/pi modules)
- Fix lib output: use nixpkgs.lib directly instead of instantiating
  a full nixpkgs just to get lib
- Add lib unit tests to flake checks
- Update stale comment in coding-rules.nix
2026-04-18 10:15:50 +00:00
Chiron c9ecc0809f fix: add externalSkills option to pi agent module
Skills from flake inputs (e.g. Basecamp) were not being passed to
mkOpencodeSkills for the pi agent, so they never appeared in
~/.pi/agent/skills/. This adds the same externalSkills option that
the opencode agent module already has.
2026-04-18 10:07:44 +00:00
Chiron 44c7e0d19a chore: sync non-pi changes from remote (eigent update, formatting fixes, gitignore) 2026-04-18 10:05:59 +00:00
ChironandChiron a0f4d401df docs: update AGENTS.md to reflect current codebase state 2026-04-18 10:05:16 +00:00
ChironandChiron d04d405297 test: add basic lib function tests for agents and coding-rules 2026-04-18 10:05:16 +00:00
ChironandChiron 2494da1054 docs: add CHANGELOG.md 2026-04-18 10:05:16 +00:00
ChironandChiron b2c8c935af refactor: remove redundant 'additions' overlay (identical to 'default') 2026-04-18 10:05:16 +00:00
ChironandChiron c6d8376dda refactor: tool-agnostic naming in coding-rules.nix internals 2026-04-18 10:05:16 +00:00
ChironandChiron 0331316755 chore: remove dead overlay entries for non-existent flake inputs 2026-04-18 10:05:16 +00:00
ChironandChiron a4e540630d docs: clarify system binding in pkgs/default.nix 2026-04-18 10:05:16 +00:00
ChironandChiron 6c985c640d refactor: remove duplicate opencode-rules.nix, use alias in default.nix 2026-04-18 10:05:16 +00:00
ChironandChiron 5f90f16d99 docs: add cleanup and improvements plan 2026-04-18 10:05:16 +00:00
m3tam3re 613e9223e4 Merge pull request 'vibetyper-1.2.2' (#4) from feature/vibetyper-1.2.2 into master
Reviewed-on: #4
2026-04-13 18:51:56 +02:00
m3tm3re 03ffb69526 flake-update 2026-04-13 18:40:27 +02:00
m3tam3re 7d231f0a05 Merge pull request 'flake-update' (#2) from chore/flake-update into master
Reviewed-on: #2
2026-04-13 17:35:49 +02:00
m3tm3re b6f13f06d0 flake-update 2026-04-13 17:35:08 +02:00
m3tam3re 72f4784445 Merge pull request 'feature/agents-rework' (#1) from feature/agents-rework into master
Reviewed-on: #1
2026-04-13 17:06:23 +02:00
m3tm3re 3d8f9e3003 feat: config with agents rework 2026-04-13 16:52:47 +02:00
m3tm3re 6426490fe7 feat(lib): implement OpenCode renderer in agents.nix 2026-04-10 17:10:46 +02:00
m3tm3re 8dfe6a8356 feat(lib): add agents.nix with loadCanonical and renderer stubs 2026-04-10 16:47:55 +02:00
sascha.koenig 1a9a60b0db chore: rename oh-my-opencode
Update Nix Packages with nix-update / nix-update (push) Failing after 3m14s
2026-04-09 13:58:45 +02:00
m3tm3re 77833a7eca flake update
Update Nix Packages with nix-update / nix-update (push) Failing after 8m0s
2026-04-08 17:47:20 +02:00
m3tm3re 715d06e83b +vibetyper + eigent
Update Nix Packages with nix-update / nix-update (push) Failing after 6m8s
2026-04-06 18:38:15 +02:00
m3tm3re 19332ebb74 openshell: 0.0.22 -> 0.0.23 2026-04-06 18:23:44 +02:00
m3tm3re b65bbcacbe openshell: 0.0.16 -> 0.0.22 2026-04-05 04:16:24 +02:00
m3tm3re feb5dcd673 -openwork
Update Nix Packages with nix-update / nix-update (push) Failing after 2m13s
2026-04-03 15:18:06 +02:00
m3tm3re c6740493b4 -openwork 2026-04-03 15:17:15 +02:00
m3tm3re 53220ae007 fix: remove openwork sidecars in preFixup to prevent .opencode-wrapped conflict 2026-04-03 12:44:45 +02:00
m3tm3re ccd2e7df08 fix: .desktop for vibetyper 2026-04-03 11:23:56 +02:00
m3tm3reandSisyphus ec6b3b9683 fix: remove sidecar binaries from openwork $out/bin to fix buildEnv conflict
openwork bundles opencode and other sidecars into bin/ during postFixup.
These are internal Tauri app resources, not user-facing executables.
When both openwork and opencode are installed in home-manager, buildEnv
fails with a conflict on .opencode-wrapped.

Remove sidecar binaries (opencode, opencode-router, openwork-server,
openwork-orchestrator, chrome-devtools-mcp, versions.json) from $out/bin
in postFixup so they don't leak into the top-level profile.

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-04-03 11:13:10 +02:00
m3tm3re 85fd377ab1 feat: openwork + vibetyper 2026-04-03 10:58:03 +02:00
sascha.koenig cd3c5ed9ad fix: formatting opencode module 2026-04-03 08:31:15 +02:00
sascha.koenig df3c1f6e70 flake update
Update Nix Packages with nix-update / nix-update (push) Failing after 1m57s
2026-04-01 14:14:14 +02:00
sascha.koenig 561b174ddc flake update 2026-04-01 14:10:41 +02:00
sascha.koenig e915e5ea19 feat: move opencode config into m3ta-nixpkgs
Update Nix Packages with nix-update / nix-update (push) Failing after 6m3s
2026-03-30 19:04:24 +02:00
sascha.koenig 7e09e3b5ed feat: move opencode config into m3ta-nixpkgs 2026-03-30 19:04:09 +02:00
nix-update bot a63f91d25b chore: update flake inputs - opencode(v1.3.6)
Update Nix Packages with nix-update / nix-update (push) Failing after 6m7s
2026-03-30 04:01:20 +02:00
nix-update bot 53671a4717 chore: update flake inputs - opencode(v1.3.5)
Update Nix Packages with nix-update / nix-update (push) Successful in 58m33s
2026-03-29 16:00:56 +02:00
nix-update bot 5c7156a93c mem0: 1.0.7 -> 1.0.9
Update Nix Packages with nix-update / nix-update (push) Successful in 45m51s
Diff: https://github.com/mem0ai/mem0/compare/v1.0.7...v1.0.9

Changelog: https://github.com/mem0ai/mem0/releases/tag/v1.0.9
2026-03-29 04:01:54 +02:00
nix-update bot c72bd4fdc8 chore: update flake inputs - opencode(v1.3.4) 2026-03-29 04:01:02 +02:00
m3tm3re 564d209402 fix: some nix eval warnings
Update Nix Packages with nix-update / nix-update (push) Successful in 46m52s
2026-03-28 10:08:36 +01:00
sascha.koenig 0f2693a812 feat: +basecamp-cli
Update Nix Packages with nix-update / nix-update (push) Failing after 7m22s
2026-03-27 11:56:04 +01:00
nix-update bot b85be2cec0 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Failing after 8m9s
2026-03-26 15:01:03 +01:00
nix-update bot 0aa01e3738 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m32s
2026-03-26 03:01:26 +01:00
m3tm3re 6d8bcbb27b chore: ci-update
Update Nix Packages with nix-update / nix-update (push) Successful in 40m47s
2026-03-25 19:11:57 +01:00
m3tm3re 27eb412218 kestractl: 1.0.0 -> 1.2.2 2026-03-25 19:10:35 +01:00
m3tm3re 038afafd33 openshell: 0.0.14 -> 0.0.16 2026-03-25 19:10:23 +01:00
nix-update bot 39931b3eab td: 0.42.2 -> 0.43.0
Update Nix Packages with nix-update / nix-update (push) Failing after 7m40s
Diff: https://github.com/marcus/td/compare/v0.42.2...v0.43.0
2026-03-24 15:07:04 +01:00
nix-update bot 151dde22f6 sidecar: 0.80.0 -> 0.83.0
Diff: https://github.com/marcus/sidecar/compare/v0.80.0...v0.83.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.83.0
2026-03-24 15:06:36 +01:00
nix-update bot db57ddae1f chore: update flake inputs 2026-03-24 15:01:03 +01:00
nix-update bot 66480706fa chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 9m57s
2026-03-24 03:01:05 +01:00
m3tm3re 418c3b1331 feat: add openshell package
Update Nix Packages with nix-update / nix-update (push) Successful in 35m25s
2026-03-23 19:56:15 +01:00
nix-update bot 99d281fd4f chore: update flake inputs - opencode(v1.3.0)
Update Nix Packages with nix-update / nix-update (push) Failing after 1h2m35s
2026-03-23 03:01:04 +01:00
nix-update bot e98be80e55 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Failing after 1h2m33s
2026-03-22 15:00:45 +01:00
nix-update bot f084f3a4f5 td: 0.42.1 -> 0.42.2
Update Nix Packages with nix-update / nix-update (push) Successful in 2m35s
Diff: https://github.com/marcus/td/compare/v0.42.1...v0.42.2
2026-03-22 03:02:59 +01:00
nix-update bot d1b7cd99e2 sidecar: 0.79.0 -> 0.80.0
Diff: https://github.com/marcus/sidecar/compare/v0.79.0...v0.80.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.80.0
2026-03-22 03:02:32 +01:00
nix-update bot 6b04156750 chore: update flake inputs 2026-03-22 03:00:46 +01:00
nix-update bot 10ef69b99f td: 0.42.0 -> 0.42.1
Update Nix Packages with nix-update / nix-update (push) Successful in 5m56s
Diff: https://github.com/marcus/td/compare/v0.42.0...v0.42.1
2026-03-21 15:03:00 +01:00
nix-update bot ef786fd0b1 sidecar: 0.78.0 -> 0.79.0
Diff: https://github.com/marcus/sidecar/compare/v0.78.0...v0.79.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.79.0
2026-03-21 15:02:34 +01:00
nix-update bot 15fff9fb99 chore: update flake inputs 2026-03-21 15:00:47 +01:00
nix-update bot 25968af711 mem0: 1.0.6 -> 1.0.7
Update Nix Packages with nix-update / nix-update (push) Successful in 6m1s
Diff: https://github.com/mem0ai/mem0/compare/v1.0.6...v1.0.7

Changelog: https://github.com/mem0ai/mem0/releases/tag/v1.0.7
2026-03-21 03:01:45 +01:00
nix-update bot 595d0a23a9 chore: update flake inputs 2026-03-21 03:00:47 +01:00
nix-update bot 38b4514fe1 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 35m40s
2026-03-20 15:00:50 +01:00
nix-update bot 7f2c76a7de chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 36m49s
2026-03-20 03:00:46 +01:00
nix-update bot c6c2aa767f chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m30s
2026-03-19 15:01:06 +01:00
nix-update bot df034046eb chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 3m4s
2026-03-19 03:00:47 +01:00
nix-update bot 5dd6d79b80 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 2m31s
2026-03-18 15:01:06 +01:00
nix-update bot 5ce015afa3 mem0: 1.0.5 -> 1.0.6
Update Nix Packages with nix-update / nix-update (push) Successful in 4m51s
Diff: https://github.com/mem0ai/mem0/compare/v1.0.5...v1.0.6

Changelog: https://github.com/mem0ai/mem0/releases/tag/v1.0.6
2026-03-18 03:01:42 +01:00
nix-update bot 259d2ee82b chore: update flake inputs 2026-03-18 03:00:45 +01:00
nix-update bot 53c9b62390 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 6m4s
2026-03-17 15:00:47 +01:00
nix-update bot 8387fcfa9b chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 6m0s
2026-03-17 03:01:08 +01:00
nix-update bot 1aa1f23ce4 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 4m31s
2026-03-16 15:01:06 +01:00
sascha.koenig 1925c91a38 chore: update docs
Update Nix Packages with nix-update / nix-update (push) Failing after 32m41s
2026-03-16 10:28:25 +01:00
sascha.koenig 424c212194 +kestracli 2026-03-16 10:27:54 +01:00
nix-update bot 29d1cdf894 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Failing after 6m48s
2026-03-10 15:01:05 +01:00
nix-update bot 7551a6b919 td: 0.41.0 -> 0.42.0
Update Nix Packages with nix-update / nix-update (push) Successful in 18m27s
Diff: https://github.com/marcus/td/compare/v0.41.0...v0.42.0
2026-03-10 03:04:11 +01:00
nix-update bot 8bb7211ccc sidecar: 0.77.0 -> 0.78.0
Diff: https://github.com/marcus/sidecar/compare/v0.77.0...v0.78.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.78.0
2026-03-10 03:03:56 +01:00
nix-update bot 25512af24c chore: update flake inputs - opencode(v1.2.24) 2026-03-10 03:01:25 +01:00
nix-update bot 3bd2f23e0d chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 25m46s
2026-03-08 15:01:10 +01:00
nix-update bot 22b43adbb2 chore: update flake inputs - opencode(v1.2.21)
Update Nix Packages with nix-update / nix-update (push) Successful in 2m43s
2026-03-08 03:01:17 +01:00
nix-update bot 140b5cb682 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 19m54s
2026-03-07 15:01:02 +01:00
m3tm3re 291e3a0744 docs: update docs for removed packages (opencode, beads)
Update Nix Packages with nix-update / nix-update (push) Successful in 14m5s
- Fix broken beads reference in pkgs/default.nix
- Convert opencode.md to deprecation notice with llm-agents.nix link
- Convert beads.md to removal notice
- Remove beads, opencode, openspec from README.md packages table
- Remove beads, opencode from docs/README.md packages list
2026-03-07 10:46:06 +01:00
m3tm3re e830d37a9e chore: removed opencode 2026-03-07 10:03:16 +01:00
nix-update bot eb9744a01d notesmd-cli: 0.3.1 -> 0.3.2
Diff: https://github.com/Yakitrak/notesmd-cli/compare/v0.3.1...v0.3.2
2026-03-07 03:03:14 +01:00
nix-update bot 74f23ed9f1 chore: update flake inputs 2026-03-07 03:00:48 +01:00
nix-update bot 2d0311cd15 chore: update flake inputs - opencode(v1.2.20)
Update Nix Packages with nix-update / nix-update (push) Successful in 3m26s
2026-03-06 15:00:53 +01:00
nix-update bot 3e49f81c76 beads: 0.58.0 -> 0.59.0
Update Nix Packages with nix-update / nix-update (push) Successful in 21m28s
Diff: https://github.com/steveyegge/beads/compare/v0.58.0...v0.59.0
2026-03-06 03:01:45 +01:00
nix-update bot 2d2c545c10 chore: update flake inputs - opencode(v1.2.18) 2026-03-06 03:00:53 +01:00
nix-update bot 106aa3749f chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 22m5s
2026-03-05 15:00:57 +01:00
nix-update bot 89197e81e4 chore: update flake inputs - opencode(v1.2.17)
Update Nix Packages with nix-update / nix-update (push) Successful in 3m32s
2026-03-05 03:00:52 +01:00
nix-update bot 8ab4fba471 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 21m4s
2026-03-04 15:00:48 +01:00
nix-update bot 3ebda192e9 mem0: 1.0.4 -> 1.0.5
Update Nix Packages with nix-update / nix-update (push) Successful in 2m56s
Diff: https://github.com/mem0ai/mem0/compare/v1.0.4...v1.0.5

Changelog: https://github.com/mem0ai/mem0/releases/tag/v1.0.5
2026-03-04 03:01:27 +01:00
nix-update bot 68964eb099 chore: update flake inputs - opencode(v1.2.16) 2026-03-04 03:01:03 +01:00
nix-update bot 7b9fc8f280 beads: 0.57.0 -> 0.58.0
Update Nix Packages with nix-update / nix-update (push) Successful in 21m25s
Diff: https://github.com/steveyegge/beads/compare/v0.57.0...v0.58.0
2026-03-03 15:01:17 +01:00
nix-update bot 1fe74b6d7d chore: update flake inputs 2026-03-03 15:00:48 +01:00
nix-update bot 11f3da30c3 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 3m44s
2026-03-03 03:00:57 +01:00
nix-update bot be401c2ebb chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 16m41s
2026-03-02 15:00:48 +01:00
nix-update bot 41e6ea8280 chore: update flake inputs
Update Nix Packages with nix-update / nix-update (push) Successful in 1m11s
2026-03-02 03:00:54 +01:00
nix-update bot 6693c09465 sidecar: 0.76.0 -> 0.77.0
Update Nix Packages with nix-update / nix-update (push) Successful in 21m31s
Diff: https://github.com/marcus/sidecar/compare/v0.76.0...v0.77.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.77.0
2026-03-01 15:01:46 +01:00
nix-update bot 51d79fbbcf beads: 0.56.1 -> 0.57.0
Diff: https://github.com/steveyegge/beads/compare/v0.56.1...v0.57.0
2026-03-01 15:01:16 +01:00
nix-update bot 9ef17eb7eb chore: update flake inputs 2026-03-01 15:00:47 +01:00
nix-update bot 81cffd22cb td: 0.38.0 -> 0.41.0
Update Nix Packages with nix-update / nix-update (push) Successful in 2m29s
Diff: https://github.com/marcus/td/compare/v0.38.0...v0.41.0
2026-03-01 03:02:14 +01:00
nix-update bot c2c0201295 sidecar: 0.74.1 -> 0.76.0
Diff: https://github.com/marcus/sidecar/compare/v0.74.1...v0.76.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.76.0
2026-03-01 03:01:58 +01:00
nix-update bot 47cace3dd1 beads: 0.49.1 -> 0.56.1
Diff: https://github.com/steveyegge/beads/compare/v0.49.1...v0.56.1
2026-03-01 03:01:26 +01:00
nix-update bot bfa707c11d chore: update flake inputs - opencode(v1.2.15) 2026-03-01 03:00:59 +01:00
m3tm3re e22774539a chore: manual update until I find the time to fix CI/CD
Update Nix Packages with nix-update / nix-update (push) Successful in 18m47s
2026-02-25 18:52:11 +01:00
m3tm3re 166ed9e825 fix: n8n build error
Update Nix Packages with nix-update / nix-update (push) Failing after 3m13s
2026-02-21 18:30:27 +01:00
m3tm3re 5b55f47020 fix(n8n): restructure version handling for nix-update compatibility
Update Nix Packages with nix-update / nix-update (push) Failing after 4m29s
- Store version without 'n8n@' prefix (e.g., '2.8.3' not 'n8n@2.8.3')
- Construct tag with prefix: tag = "n8n@${version}"
- Update to version 2.8.3 with correct hashes

This allows nix-update to work correctly with the custom update.sh
script that strips the 'n8n@' prefix from GitHub release tags.
2026-02-20 09:47:23 +01:00
nix-update bot f95fe5bf6d td: 0.37.0 -> 0.38.0
Diff: https://github.com/marcus/td/compare/v0.37.0...v0.38.0
2026-02-20 09:03:52 +01:00
nix-update bot 34dda52d53 sidecar: 0.74.0 -> 0.74.1
Diff: https://github.com/marcus/sidecar/compare/v0.74.0...v0.74.1

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.74.1
2026-02-20 09:03:38 +01:00
nix-update bot 06a40240ea notesmd-cli: 0.3.0 -> 0.3.1
Diff: https://github.com/Yakitrak/notesmd-cli/compare/v0.3.0...v0.3.1
2026-02-20 09:03:22 +01:00
nix-update bot ad0bc14461 mem0: 1.0.3 -> 1.0.4
Diff: https://github.com/mem0ai/mem0/compare/v1.0.3...v1.0.4

Changelog: https://github.com/mem0ai/mem0/releases/tag/v1.0.4
2026-02-20 09:03:04 +01:00
nix-update bot 6d262127e7 chore: update flake inputs - opencode(v1.2.9) 2026-02-20 09:02:42 +01:00
m3tm3re 839d7ae743 feat(ci): support custom update scripts for specific packages
Add detection logic to distinguish between:
- nix-update-script (standard packages like beads, td, mem0, etc.)
- Custom scripts (like n8n's update.sh that strips 'n8n@' prefix)

For custom scripts, run them directly with standard env vars:
- UPDATE_NIX_NAME, UPDATE_NIX_PNAME
- UPDATE_NIX_OLD_VERSION, UPDATE_NIX_ATTR_PATH

This ensures n8n only gets stable releases via its custom script.
2026-02-20 09:01:06 +01:00
m3tm3re 2e37c16ac7 fix(ci): resolve nix-update workflow issues
- Remove --use-update-script flag that breaks with flake-only repos
  (nix-update-script expects default.nix at repo root)
- Fix GitHub API jq filter for detecting prereleases
- Fix Summary step bash syntax for handling input variables
- Format lib/ files that were failing formatting check
2026-02-20 08:30:26 +01:00
m3tm3re 3b99d1215e fix: n8n update script 2026-02-20 08:13:46 +01:00
m3tm3re f05865972b fix(ci): dynamic flake input discovery and updateScript support
- Replace hardcoded opencode update step with dynamic discovery of all
  version-pinned flake inputs via nix flake metadata --json
- Add --use-update-script flag to nix-update command so packages with
  custom passthru.updateScript (like n8n) use their custom scripts
- Update output variables from update-opencode to update-flake-inputs
- Update Summary step to reflect new generic flake input handling
2026-02-20 07:51:21 +01:00
m3tm3re 58312b2ca2 feat: add openspec package
Update Nix Packages with nix-update / nix-update (push) Failing after 23s
2026-02-18 17:55:07 +01:00
m3tm3re dc206b13e2 feat(shells): add opencode dev shell with mkOpencodeRules demo
Update Nix Packages with nix-update / nix-update (push) Failing after 2m27s
2026-02-17 20:16:11 +01:00
m3tm3re d43bb33dcb feat(lib): add opencode-rules helper for per-project rule injection
- Create lib/opencode-rules.nix with mkOpencodeRules function
- Update lib/default.nix to import opencode-rules module
- Pattern follows ports.nix: {lib}: { mkOpencodeRules = ...; }

Refs: T2, T3 of rules-system plan
2026-02-17 18:59:43 +01:00
nix-update bot d2ec6a0474 sidecar: 0.73.1 -> 0.74.0
Update Nix Packages with nix-update / nix-update (push) Failing after 5m34s
Diff: https://github.com/marcus/sidecar/compare/v0.73.1...v0.74.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.74.0
2026-02-17 03:18:11 +01:00
nix-update bot f69dd15474 chore: update opencode flake input to 1.2.6 2026-02-17 03:17:38 +01:00
nix-update bot c7935658e6 td: 0.36.0 -> 0.37.0
Update Nix Packages with nix-update / nix-update (push) Successful in 18m53s
Diff: https://github.com/marcus/td/compare/v0.36.0...v0.37.0
2026-02-16 03:29:20 +01:00
nix-update bot af56407296 sidecar: 0.72.0 -> 0.73.1
Diff: https://github.com/marcus/sidecar/compare/v0.72.0...v0.73.1

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.73.1
2026-02-16 03:29:06 +01:00
nix-update bot 51dd2be6ea chore: update opencode flake input to 1.2.5 2026-02-16 03:28:33 +01:00
nix-update bot 6ebd7b94d5 td: 0.34.0 -> 0.36.0
Update Nix Packages with nix-update / nix-update (push) Successful in 30m36s
Diff: https://github.com/marcus/td/compare/v0.34.0...v0.36.0
2026-02-15 03:18:42 +01:00
nix-update bot 22bfba739d sidecar: 0.71.1 -> 0.72.0
Diff: https://github.com/marcus/sidecar/compare/v0.71.1...v0.72.0

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.72.0
2026-02-15 03:18:28 +01:00
nix-update bot 9d27e48b2b chore: update opencode flake input to 1.2.4 2026-02-15 03:17:54 +01:00
nix-update bot 3f26c44b5a chore: update opencode flake input to 1.2.1
Update Nix Packages with nix-update / nix-update (push) Successful in 19m58s
2026-02-14 15:19:39 +01:00
m3tm3re 6775659538 chore: remove .sidecar-* files from tracking
Update Nix Packages with nix-update / nix-update (push) Successful in 20m2s
2026-02-14 07:34:08 +01:00
m3tm3re b80422c16e chore: ignore all .sidecar-* files 2026-02-14 07:31:57 +01:00
m3tm3re a6c1d7cf97 chore: add AI agent directories to gitignore 2026-02-14 07:30:35 +01:00
m3tm3re e6c22a04d7 feat: add notesmd-cli package and flake checks
- Add notesmd-cli package for Obsidian CLI interaction
- Add flake checks for package build verification
- Add documentation for notesmd-cli, sidecar, and td
- Update AGENTS.md to reference td instead of beads
- Format pkgs/default.nix with proper braces
2026-02-14 07:15:06 +01:00
nix-update bot 56a7a7bfa8 n8n: n8n@2.8.1 -> n8n@2.7.5
Diff: https://github.com/n8n-io/n8n/compare/n8n@2.8.1...n8n@2.7.5

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.7.5
2026-02-14 03:02:08 +01:00
nix-update bot 42cd0849b4 n8n: n8n@2.7.4 -> n8n@2.8.1
Update Nix Packages with nix-update / nix-update (push) Successful in 8m45s
Diff: https://github.com/n8n-io/n8n/compare/n8n@2.7.4...n8n@2.8.1

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.8.1
2026-02-13 06:56:31 +01:00
nix-update bot 47b622745d chore: update opencode flake input to 1.1.65 2026-02-13 06:54:31 +01:00
sascha.koenig fbeb39ec22 Merge branch 'bugfix-opencode-flake-input' 2026-02-13 06:51:03 +01:00
sascha.koenig 8ab5b4de8d fix: gitea runner opencode.url flake input 2026-02-13 06:50:44 +01:00
m3tm3re dc2f3b6802 feat: update opencode to v1.1.60 and re-enable opencode-desktop
Update Nix Packages with nix-update / nix-update (push) Failing after 1s
- Update opencode flake input to v1.1.60
- Add nixpkgs-master input for opencode (needs newer bun)
- Re-enable opencode-desktop with workaround for upstream issue #11755
- Add specta/tauri outputHashes for git dependencies
- Add .todos/ to gitignore
- Update AGENTS.md with td task management instructions
2026-02-12 19:42:11 +01:00
m3tm3re 909acf61d3 add opencode to sidecar deps
Update Nix Packages with nix-update / nix-update (push) Successful in 25s
2026-02-11 19:58:52 +01:00
m3tm3re 105629502a fix: add tmux to sidecar deps 2026-02-11 18:03:31 +01:00
nix-update bot f1fff4245f td: 0.33.0 -> 0.34.0
Diff: https://github.com/marcus/td/compare/v0.33.0...v0.34.0
2026-02-11 15:04:45 +01:00
nix-update bot d85f2df603 n8n: n8n@2.6.4 -> n8n@2.7.4
Diff: https://github.com/n8n-io/n8n/compare/n8n@2.6.4...n8n@2.7.4

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.7.4
2026-02-11 15:04:27 +01:00
nix-update bot f6af27e960 chore: update opencode flake input to 1.1.57 2026-02-11 15:02:32 +01:00
nix-update bot 19456800ed sidecar: 0.71.0 -> 0.71.1
Update Nix Packages with nix-update / nix-update (push) Successful in 12m34s
Diff: https://github.com/marcus/sidecar/compare/v0.71.0...v0.71.1

Changelog: https://github.com/marcus/sidecar/releases/tag/v0.71.1
2026-02-11 03:03:29 +01:00
nix-update bot 8dac838645 chore: update opencode flake input to 1.1.56 2026-02-11 03:02:55 +01:00
sascha.koenig 644c7eac5d feat: add sidecar and td packages, fix neovim extraLuaConfig
Update Nix Packages with nix-update / nix-update (push) Successful in 4m18s
2026-02-10 08:33:38 +01:00
sascha.koenig 90a5344f62 flake.lock: Update
Flake lock file updates:

• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/ffbc9f8cbaacfb331b6017d5a5abb21a492c9a38?narHash=sha256-1Sm77VfZh3mU0F5OqKABNLWxOuDeHIlcFjsXeeiPazs%3D' (2026-01-11)
  → 'github:NixOS/nixpkgs/d6c71932130818840fc8fe9509cf50be8c64634f?narHash=sha256-ub1gpAONMFsT/GU2hV6ZWJjur8rJ6kKxdm9IlCT0j84%3D' (2026-02-08)
2026-02-10 06:52:53 +01:00
nix-update bot 8751ef9b1f n8n: n8n@2.4.8 -> n8n@2.6.4
Update Nix Packages with nix-update / nix-update (push) Successful in 17s
Diff: https://github.com/n8n-io/n8n/compare/n8n@2.4.8...n8n@2.6.4

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.6.4
2026-02-09 19:16:43 +01:00
nix-update bot de0bdd8ae3 mem0: 1.0.2 -> 1.0.3
Diff: https://github.com/mem0ai/mem0/compare/v1.0.2...v1.0.3

Changelog: https://github.com/mem0ai/mem0/releases/tag/v1.0.3
2026-02-09 19:13:14 +01:00
nix-update bot caa2fd57dd chore: update opencode flake input to 1.1.53 2026-02-09 19:12:57 +01:00
m3tm3re 62ce3dc646 fix(workflow): sequential updates with cleanup on failure
- Run nix-update sequentially instead of parallel to avoid race conditions
- Clean up uncommitted changes after failed updates (git checkout/clean)
- Simplify push logic by removing stash/pop complexity
- Remove upload-artifact@v4 (unsupported on Gitea Actions)
2026-02-09 19:12:22 +01:00
m3tm3re 3c87721011 docs: document opencode-desktop workaround (upstream #11755)
Update Nix Packages with nix-update / nix-update (push) Failing after 2m21s
2026-02-07 15:10:21 +01:00
m3tm3re 4c81a909a3 fix(workflow): add git stash and pre-push validation 2026-02-07 15:07:13 +01:00
m3tm3re 112db85fa1 fix: extraLuaConfig renamed initLua
Update Nix Packages with nix-update / nix-update (push) Successful in 2m21s
2026-02-04 20:01:54 +01:00
m3tm3re 0b08fb400e -opencode-desktop until upstream fixed 2026-02-04 19:54:06 +01:00
nix-update bot 51b8a8296c chore: update opencode flake input to 1.1.47
Update Nix Packages with nix-update / nix-update (push) Failing after 14s
2026-01-31 03:03:04 +01:00
nix-update bot be44229e5a chore: update opencode flake input to 1.1.44
Update Nix Packages with nix-update / nix-update (push) Successful in 3m11s
2026-01-30 15:02:21 +01:00
nix-update bot f203bb7463 n8n: n8n@2.4.7 -> n8n@2.4.8
Update Nix Packages with nix-update / nix-update (push) Successful in 2m29s
Diff: https://github.com/n8n-io/n8n/compare/n8n@2.4.7...n8n@2.4.8

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.4.8
2026-01-30 03:03:30 +01:00
nix-update bot 12e8baadf2 chore: update opencode flake input to 1.1.43 2026-01-30 03:01:49 +01:00
nix-update bot 4232a5ccc9 n8n: n8n@2.4.6 -> n8n@2.4.7
Update Nix Packages with nix-update / nix-update (push) Successful in 9m48s
Diff: https://github.com/n8n-io/n8n/compare/n8n@2.4.6...n8n@2.4.7

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.4.7
2026-01-29 15:03:48 +01:00
nix-update bot a8700a6e8c chore: update opencode flake input to 1.1.42 2026-01-29 15:02:03 +01:00
nix-update bot 2e31c2ff23 chore: update opencode flake input to 1.1.40
Update Nix Packages with nix-update / nix-update (push) Successful in 10m24s
2026-01-29 03:03:18 +01:00
nix-update bot 1323c91f1e chore: update opencode flake input to 1.1.39
Update Nix Packages with nix-update / nix-update (push) Successful in 3m25s
2026-01-28 15:02:49 +01:00
nix-update bot 9cff518954 beads: 0.49.0 -> 0.49.1
Update Nix Packages with nix-update / nix-update (push) Successful in 2m57s
Diff: https://github.com/steveyegge/beads/compare/v0.49.0...v0.49.1
2026-01-26 15:00:49 +01:00
m3tm3re 308a60888b fix: stt-ptt use pkill for better process management
Update Nix Packages with nix-update / nix-update (push) Successful in 2m34s
2026-01-26 05:16:29 +01:00
nix-update bot 932dffce51 chore: update opencode flake input to 1.1.36 2026-01-26 03:03:32 +01:00
nix-update bot 0a64f5cdc6 chore: update opencode flake input to 1.1.35
Update Nix Packages with nix-update / nix-update (push) Successful in 3m41s
2026-01-25 03:02:28 +01:00
nix-update bot ec315e0534 n8n: n8n@2.4.5 -> n8n@2.4.6
Update Nix Packages with nix-update / nix-update (push) Successful in 2m35s
Diff: https://github.com/n8n-io/n8n/compare/n8n@2.4.5...n8n@2.4.6

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.4.6
2026-01-24 03:02:00 +01:00
m3tm3re b76fbefc4b feat: add opencode-desktop package with Wayland support
Update Nix Packages with nix-update / nix-update (push) Successful in 8m21s
2026-01-23 17:52:46 +01:00
nix-update bot 7a0f5bfd18 chore: update opencode flake input to 1.1.34 2026-01-23 15:02:09 +01:00
nix-update bot 7feaf3568f chore: update opencode flake input to 1.1.32
Update Nix Packages with nix-update / nix-update (push) Successful in 2m16s
2026-01-23 03:02:23 +01:00
nix-update bot 38e58702df n8n: n8n@2.4.4 -> n8n@2.4.5
Update Nix Packages with nix-update / nix-update (push) Successful in 2m31s
Diff: https://github.com/n8n-io/n8n/compare/n8n@2.4.4...n8n@2.4.5

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.4.5
2026-01-22 18:34:04 +01:00
nix-update bot f91695eb38 beads: 0.47.1 -> 0.49.0
Diff: https://github.com/steveyegge/beads/compare/v0.47.1...v0.49.0
2026-01-22 18:33:03 +01:00
nix-update bot d4ba11c7a3 chore: update opencode flake input to 1.1.31 2026-01-22 18:32:09 +01:00
m3tm3re bd0e8f2785 chore: removed temporary fix for opencode bun version requirement 2026-01-22 18:30:40 +01:00
nix-update bot fb5f3e9447 beads: 0.48.0 -> 0.47.1
Update Nix Packages with nix-update / nix-update (push) Failing after 2m11s
Diff: https://github.com/steveyegge/beads/compare/v0.48.0...v0.47.1
2026-01-21 18:03:12 +01:00
nix-update bot a1d3de6370 chore: update opencode flake input to 1.1.28
Update Nix Packages with nix-update / nix-update (push) Successful in 6s
2026-01-21 07:19:27 +01:00
sascha.koenig 9c4853f5fb fix: nix fmt without arg in workflow 2026-01-21 07:17:01 +01:00
m3tm3re d674b2f02b fix: gitea workflow
Update Nix Packages with nix-update / nix-update (push) Waiting to run
2026-01-20 20:57:31 +01:00
m3tm3re 1c7a7f0c82 fix: remove deprecated opencode update logic 2026-01-20 19:36:51 +01:00
m3tm3re 4597384291 fix(opencode): patch bun version requirement to match upstream lockfile
- Upstream v1.1.27 requires Bun 1.3.5 but provides 1.3.6
- Patch package.json to accept Bun 1.3.6
- Propagate patched opencode to opencode-desktop
2026-01-20 18:49:18 +01:00
m3tm3re de3850fb1b feat: replace local opencode with upstream flake input v1.1.27
- Add `opencode` flake input pinned to v1.1.27 for stability
- Remove local `pkgs/opencode` derivation and overlay
- Add `opencode` and `opencode-desktop` to `pkgs/default.nix` from input
2026-01-20 18:32:28 +01:00
m3tm3re d3809a7b5e fix: arithmetic increment failing with set -e in nix-update workflow 2026-01-19 18:22:01 +01:00
m3tm3re 58868d0867 fix: remove magic-nix-cache-action causing platform mapping error
Update Nix Packages with nix-update / nix-update (push) Failing after 8s
Removed DeterminateSystems/magic-nix-cache-action to resolve "Cannot convert ArchOs (amd64-linux)" error in Gitea Actions. The action is GitHub-specific and doesn't work with act_runner's platform detection. Workflow will now use default cache.nixos.org substituter.

Note: Consider migrating to Attic binary cache for better performance in the future.
2026-01-18 19:44:58 +01:00
m3tm3re 286fa08b70 feat: optimize nix-update workflow with caching and parallel processing
- Add Magic Nix Cache for 3-9x faster builds
- Add --use-github-releases to only update stable versions
- Remove SKIP_PACKAGES, use dynamic discovery via passthru.updateScript
- Implement 4 concurrent update jobs for 4x speedup
- Add nix flake check for comprehensive validation
- Collect all build failures instead of failing on first
- Fix git reset bug that was destroying commits
- Add job timeout to prevent hanging
- Add detailed job summary and log artifacts
2026-01-18 19:11:46 +01:00
nix-update bot c8a987c43e n8n: 2.4.1 -> n8n@2.4.4
Update Nix Packages with nix-update / nix-update (push) Successful in 15s
Diff: https://github.com/n8n-io/n8n/compare/2.4.1...n8n@2.4.4

Changelog: https://github.com/n8n-io/n8n/releases/tag/n8n@n8n@2.4.4
2026-01-18 11:08:31 +01:00
nix-update bot 71ad8336ce beads: 0.47.1 -> 0.48.0
Diff: https://github.com/steveyegge/beads/compare/v0.47.1...v0.48.0
2026-01-18 11:06:47 +01:00
m3tm3re f64e6983ea feat: improve nix-update workflow and update packages
- Refactor nix-update.yml: push directly to master instead of PRs
- Add skip list for packages without upstream releases
- Add opencode subpackage handling for node_modules
- Add nix-update-script to beads, code2prompt, mem0
- Update mem0: 1.0.0 -> 1.0.2
- Update opencode: 1.1.18 -> 1.1.25
- Fix n8n tag format
- Add n8n update.sh helper script
2026-01-18 11:04:33 +01:00
m3tm3re 52d8cdee11 fixed n8n pnpm hash
Update Nix Packages with nix-update / nix-update (push) Failing after 29s
2026-01-14 20:53:10 +01:00
m3tm3re 60388970e0 bd sync: 2026-01-14 20:52:11 2026-01-14 20:52:11 +01:00
m3tm3re 6f2f1411a8 fix: correct jobs indentation in workflow 2026-01-14 20:43:18 +01:00
m3tm3re c5d5ff98f8 fix: use escaped newlines in PR body to avoid YAML parsing error 2026-01-14 20:39:40 +01:00
m3tm3re 0f4435ad93 chore: sync beads state 2026-01-14 20:36:09 +01:00
m3tm3re 36db58307a fix: resolve YAML syntax error in PR body 2026-01-14 20:32:51 +01:00
m3tm3re f2e0200568 ci: verify package builds before creating PR 2026-01-14 20:30:28 +01:00
m3tm3re 6221984a29 chore: sync beads state 2026-01-14 20:10:04 +01:00
m3tm3re 287bcfea8e ci: use self-hosted nixos runner and change schedule to daily 2026-01-14 20:09:41 +01:00
m3tm3re 42d94876d8 docs: add documentation for beads, n8n, opencode packages
- Update AGENTS.md header with current commit (366af12) and date (2026-01-13)
- Add beads, n8n, opencode to README.md Available Packages table
- Update docs/README.md packages list
- Create docs/packages/beads.md (220 lines)
- Create docs/packages/n8n.md (310 lines)
- Create docs/packages/opencode.md (346 lines)

Documentation now reflects commit bc75505 which added these three packages.
2026-01-13 21:09:02 +01:00
m3tm3re 366af129bd docs: update documentation for automated package updates workflow 2026-01-13 20:56:01 +01:00
m3tm3re b6d45cae4f feat: add Gitea Actions workflow for automated package updates with nix-update 2026-01-13 20:50:38 +01:00
m3tm3re dbc14838cd chore: update lock files and mods 2026-01-13 20:27:52 +01:00
m3tm3re bc75505ca3 feat: add n8n, beads, opencode packages
- Add pkgs/n8n/default.nix (v2.4.1)
- Add pkgs/beads/default.nix (v0.47.1, doCheck=false)
- Add pkgs/opencode/default.nix (v1.1.18)
- Include relax-bun-version-check.patch for opencode
- Register all packages in pkgs/default.nix
2026-01-13 20:26:30 +01:00
m3tm3re c67d663600 bd sync: 2026-01-13 20:26:21 2026-01-13 20:26:21 +01:00
m3tm3re 15b7b13ea1 opencode -> 1.1.18 2026-01-13 19:53:46 +01:00
m3tm3re 338aced3a8 opencode -> 1.1.14 2026-01-12 20:25:38 +01:00
m3tm3re 00b858fbbe docs: update documentation for latest changes
- Add stt-ptt language support documentation
- Add rofi-project-opener module documentation
- Add rofi-project-opener package documentation
- Update zellij-ps documentation
- Update guides and reference patterns
- Update AGENTS.md with latest commands
2026-01-10 19:12:45 +01:00
m3tm3re 6230c04a61 bd sync: 2026-01-10 19:12:32 2026-01-10 19:12:32 +01:00
m3tm3re 9f284a8c21 feat: add auto-language detection support to stt-ptt
- Add STT_LANGUAGE environment variable (default: auto)
- Modify whisper-cli call to use -l flag with language code
- Add language option to HM module (enum with 23 common languages + auto)
- Update help text to document STT_LANGUAGE variable
2026-01-10 09:36:21 +01:00
m3tm3re 3933e380c6 bd sync: 2026-01-10 08:44:29 2026-01-10 08:44:29 +01:00
m3tm3re 6af872107b opencode update 2026-01-10 06:14:21 +01:00
m3tm3re be7cd917a0 feat: update beads to v0.46.0 2026-01-08 04:19:43 +01:00
m3tm3re e146a79309 opencode -> 1.1.4 2026-01-07 17:45:42 +01:00
m3tm3re 6e6e819150 project-launcher changes 2026-01-06 05:54:39 +01:00
m3tm3re 5f8b5dbcdc bd sync: 2026-01-05 12:50:04 2026-01-05 12:50:04 +01:00
m3tm3re 586d199497 bd sync: 2026-01-05 12:46:30 2026-01-05 12:46:30 +01:00
m3tm3re 4b05e2c95f beads test 2026-01-05 12:05:39 +01:00
m3tm3re b275327469 +beads + opencode overlays 2026-01-04 04:07:00 +01:00
m3tm3re 2640d62142 +beads + opencode overlays 2026-01-04 04:03:11 +01:00
m3tm3re 0b4c2efc8f feat: add rofi-project-opener for rofi-based project launching
Adds package and HM module for quickly opening projects in terminals.
Uses XDG config file instead of environment variables for better
shell-independence and proper NixOS PATH sourcing.
2026-01-02 14:54:12 +01:00
m3tm3re de1301e08d feat: add stt-ptt package 2026-01-02 12:24:48 +01:00
m3tm3re 44485c4c72 docs: update zellij-ps to reflect project switcher functionality
- Update package description and fix mainProgram typo
- Rewrite documentation to describe project switching, not process viewing
- Add PROJECT_FOLDERS configuration and usage examples
- Update all references across docs (README, guides, module overviews)
2025-12-30 15:42:52 +01:00
m3tm3re 744b6a8243 refactor: switch formatter from nixpkgs-fmt to alejandra 2025-12-30 15:13:42 +01:00
m3tm3re 824ad97ef9 docs: add hierarchical AGENTS.md knowledge base
- Update root AGENTS.md with regenerative content (144 lines, telegraphic)
- Add pkgs/AGENTS.md for package registry conventions (33 lines)
- Add docs/AGENTS.md for documentation structure (34 lines)
- All files follow telegraphic style, no redundancy with parent
- Preserves existing modules/home-manager/AGENTS.md

Hierarchy:
  ./AGENTS.md (root)
  ├── pkgs/AGENTS.md
  ├── docs/AGENTS.md
  └── modules/home-manager/AGENTS.md (existing)
2025-12-30 15:02:58 +01:00
m3tm3re c5e161026d docs: expand AGENTS.md with comprehensive patterns and add HM module docs 2025-12-29 19:01:37 +01:00
m3tm3re 9092e6d18d +AGENTS.md 2025-12-27 10:16:52 +01:00
m3tm3re d7d64634ee n8n to 2.1.2, flake update 2025-12-23 09:26:11 +01:00
m3tm3re 0db161efac n8n to 2.0.1 2025-12-11 07:06:08 +01:00
m3tam3re a5f30c83b3 python env version fix for marimo 2025-10-14 20:45:04 +02:00
m3tam3re 11755d832f +devshell structure 2025-10-12 16:21:40 +02:00
m3tam3re 27d92a238b quckstart for port management 2025-10-05 12:44:21 +02:00
m3tam3re 8eb3693775 quckstart for port management 2025-10-05 12:43:41 +02:00
m3tam3re 735c22cf36 port module simplified 2025-10-05 12:37:57 +02:00
m3tam3re 62a85af9bc modules for ports 2025-10-05 09:44:40 +02:00
m3tam3re 56295f694d modules for ports 2025-10-05 09:19:29 +02:00
m3tam3re 4fa3a8b551 +lib +portshelper 2025-10-04 17:03:46 +02:00
m3tam3re 1ce83403bc first 2025-10-04 15:53:48 +02:00
123 changed files with 18364 additions and 7 deletions
+73
View File
@@ -0,0 +1,73 @@
# Dolt database (managed by Dolt, not git)
dolt/
embeddeddolt/
# Runtime files
bd.sock
bd.sock.startlock
sync-state.json
last-touched
.exclusive-lock
# Daemon runtime (lock, log, pid)
daemon.*
# Interactions log (runtime, not versioned)
interactions.jsonl
# Push state (runtime, per-machine)
push-state.json
# Lock files (various runtime locks)
*.lock
# Credential key (encryption key for federation peer auth — never commit)
.beads-credential-key
# Local version tracking (prevents upgrade notification spam after git ops)
.local_version
# Worktree redirect file (contains relative path to main repo's .beads/)
# Must not be committed as paths would be wrong in other clones
redirect
# Sync state (local-only, per-machine)
# These files are machine-specific and should not be shared across clones
.sync.lock
export-state/
export-state.json
# Ephemeral store (SQLite - wisps/molecules, intentionally not versioned)
ephemeral.sqlite3
ephemeral.sqlite3-journal
ephemeral.sqlite3-wal
ephemeral.sqlite3-shm
# Dolt server management (auto-started by bd)
dolt-server.pid
dolt-server.log
dolt-server.lock
dolt-server.port
dolt-server.activity
# Corrupt backup directories (created by bd doctor --fix recovery)
*.corrupt.backup/
# Backup data (auto-exported JSONL, local-only)
backup/
# Per-project environment file (Dolt connection config, GH#2520)
.env
# Legacy files (from pre-Dolt versions)
*.db
*.db?*
*.db-journal
*.db-wal
*.db-shm
db.sqlite
bd.db
# NOTE: Do NOT add negation patterns here.
# They would override fork protection in .git/info/exclude.
# Config files (metadata.json, config.yaml) are tracked by git by default
# since no pattern above ignores them.
+81
View File
@@ -0,0 +1,81 @@
# Beads - AI-Native Issue Tracking
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
## What is Beads?
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
## Quick Start
### Essential Commands
```bash
# Create new issues
bd create "Add user authentication"
# View all issues
bd list
# View issue details
bd show <issue-id>
# Update issue status
bd update <issue-id> --claim
bd update <issue-id> --status done
# Sync with Dolt remote
bd dolt push
```
### Working with Issues
Issues in Beads are:
- **Git-native**: Stored in Dolt database with version control and branching
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
- **Branch-aware**: Issues can follow your branch workflow
- **Always in sync**: Auto-syncs with your commits
## Why Beads?
**AI-Native Design**
- Built specifically for AI-assisted development workflows
- CLI-first interface works seamlessly with AI coding agents
- No context switching to web UIs
🚀 **Developer Focused**
- Issues live in your repo, right next to your code
- Works offline, syncs when you push
- Fast, lightweight, and stays out of your way
🔧 **Git Integration**
- Automatic sync with git commits
- Branch-aware issue tracking
- Dolt-native three-way merge resolution
## Get Started with Beads
Try Beads in your own projects:
```bash
# Install Beads
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
# Initialize in your repo
bd init
# Create your first issue
bd create "Try out Beads"
```
## Learn More
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
- **Quick Start Guide**: Run `bd quickstart`
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
---
*Beads: Issue tracking that moves at the speed of thought*
+56
View File
@@ -0,0 +1,56 @@
# Beads Configuration File
# This file configures default behavior for all bd commands in this repository
# All settings can also be set via environment variables (BD_* prefix)
# or overridden with command-line flags
# Issue prefix for this repository (used by bd init)
# If not set, bd init will auto-detect from directory name
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
# issue-prefix: ""
# Use no-db mode: JSONL-only, no Dolt database
# When true, bd will use .beads/issues.jsonl as the source of truth
# no-db: false
# Enable JSON output by default
# json: false
# Feedback title formatting for mutating commands (create/update/close/dep/edit)
# 0 = hide titles, N > 0 = truncate to N characters
# output:
# title-length: 255
# Default actor for audit trails (overridden by BEADS_ACTOR or --actor)
# actor: ""
# Export events (audit trail) to .beads/events.jsonl on each flush/sync
# When enabled, new events are appended incrementally using a high-water mark.
# Use 'bd export --events' to trigger manually regardless of this setting.
# events-export: false
# Multi-repo configuration (experimental - bd-307)
# Allows hydrating from multiple repositories and routing writes to the correct database
# repos:
# primary: "." # Primary repo (where this database lives)
# additional: # Additional repos to hydrate from (read-only)
# - ~/beads-planning # Personal planning repo
# - ~/work-planning # Work planning repo
# JSONL backup (periodic export for off-machine recovery)
# Auto-enabled when a git remote exists. Override explicitly:
# backup:
# enabled: false # Disable auto-backup entirely
# interval: 15m # Minimum time between auto-exports
# git-push: false # Disable git push (export locally only)
# git-repo: "" # Separate git repo for backups (default: project repo)
# Integration settings (access with 'bd config get/set')
# These are stored in the database, not in this file:
# - jira.url
# - jira.project
# - linear.url
# - linear.api-key
# - github.org
# - github.repo
sync.remote: "git+ssh://gitea@code.m3ta.dev/m3tam3re/nixpkgs.git"
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run post-checkout "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'post-checkout' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run post-checkout "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'post-checkout'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v1.0.2 ---
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run post-merge "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'post-merge' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run post-merge "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'post-merge'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v1.0.2 ---
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run pre-commit "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'pre-commit' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run pre-commit "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'pre-commit'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v1.0.2 ---
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run pre-push "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'pre-push' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run pre-push "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'pre-push'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v1.0.2 ---
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env sh
# --- BEGIN BEADS INTEGRATION v1.0.2 ---
# This section is managed by beads. Do not remove these markers.
if command -v bd >/dev/null 2>&1; then
export BD_GIT_HOOK=1
_bd_timeout=${BEADS_HOOK_TIMEOUT:-300}
if command -v timeout >/dev/null 2>&1; then
timeout "$_bd_timeout" bd hooks run prepare-commit-msg "$@"
_bd_exit=$?
if [ $_bd_exit -eq 124 ]; then
echo >&2 "beads: hook 'prepare-commit-msg' timed out after ${_bd_timeout}s — continuing without beads"
_bd_exit=0
fi
else
bd hooks run prepare-commit-msg "$@"
_bd_exit=$?
fi
if [ $_bd_exit -eq 3 ]; then
echo >&2 "beads: database not initialized — skipping hook 'prepare-commit-msg'"
_bd_exit=0
fi
if [ $_bd_exit -ne 0 ]; then exit $_bd_exit; fi
fi
# --- END BEADS INTEGRATION v1.0.2 ---
+12
View File
@@ -0,0 +1,12 @@
{"_type":"issue","id":"nixpkgs-rrw","title":"chore(downstream): migrate direct mkSkills callsites","description":"What to build\nMigrate known downstream configurations that directly call the old AGENTS skill composition API. Each migrated callsite should use the new m3ta-nixpkgs Agent Skills Library and preserve the current rendered skill behavior unless intentionally changed by the new validation rules.\n\nAcceptance criteria\n- Known direct callers of the old AGENTS skill composition API are identified.\n- Direct callers under the maintained configuration repositories are migrated to the new m3ta-nixpkgs agentSkills interface.\n- Any callsite that cannot be migrated immediately is captured as an explicit follow-up issue.\n- The migrated configuration evaluates or has a documented verification command.\n- No remaining maintained callsite depends on the removed AGENTS skill composition API.\n\nBlocked by\nIssues 7 and 11","status":"open","priority":2,"issue_type":"chore","owner":"p@m3ta.dev","created_at":"2026-05-25T09:05:32Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:05:32Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-rrw","depends_on_id":"nixpkgs-kfl","type":"blocks","created_at":"2026-05-25T11:05:50Z","created_by":"m3tam3re","metadata":"{}"},{"issue_id":"nixpkgs-rrw","depends_on_id":"nixpkgs-n5t","type":"blocks","created_at":"2026-05-25T11:05:50Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"nixpkgs-n5t","title":"docs(agents): document AGENTS as skill data source","description":"What to build\nUpdate the AGENTS repository role and documentation so AGENTS is treated as a skill data source only. Remove the old AGENTS-provided skill composition API and document the migration path to the m3ta-nixpkgs Agent Skills Library.\n\nAcceptance criteria\n- AGENTS no longer exposes the old skill composition function.\n- AGENTS documentation explains that skill composition is provided by m3ta-nixpkgs.\n- The migration path points users to the new m3ta-nixpkgs agentSkills interface.\n- References that imply AGENTS is the canonical skill composition library are removed or rewritten.\n- Documentation validation or grep-based checks confirm the obsolete API is not advertised.\n\nBlocked by\nIssue 7","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:05:27Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:05:27Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-n5t","depends_on_id":"nixpkgs-kfl","type":"blocks","created_at":"2026-05-25T11:05:50Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"_type":"issue","id":"nixpkgs-bg8","title":"feat(pi-skillset): apply active skillsets to Pi settings","description":"What to build\nComplete the pi-skillset CLI by allowing it to apply named skillsets, none, and all to Pi settings. The CLI should translate active selections into Pi-native skills patterns, preserve manual settings using the sidecar state file, and write settings and state atomically.\n\nAcceptance criteria\n- `use \u003csets...\u003e` activates all skills belonging to the named skillsets.\n- `use none` disables all catalog-managed skills.\n- `use all` activates all cataloged skills regardless of skillset membership.\n- Generated patterns use one disable-all glob for the managed skills root and exact include patterns for active skill roots.\n- Patterns are computed relative to the settings file directory in POSIX form.\n- Previously generated patterns are removed using state before new patterns are written.\n- Manual skill settings outside the generated pattern set are preserved.\n- Invalid settings JSON fails without overwriting the existing settings file.\n- Settings and state writes are atomic.\n- Successful writes tell the user to run /reload in an active Pi session.\n- Python unit tests cover named skillsets, none, all, manual preservation, state replacement, invalid JSON safety, relative paths, and reload messaging.\n\nBlocked by\nIssues 8 and 9","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:05:22Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:05:22Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-bg8","depends_on_id":"nixpkgs-e1z","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"},{"issue_id":"nixpkgs-bg8","depends_on_id":"nixpkgs-wqh","type":"blocks","created_at":"2026-05-25T11:05:50Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"nixpkgs-wqh","title":"feat(pi-skillset): add list and status commands","description":"What to build\nAdd the initial Python-based pi-skillset CLI focused on safe read-only inspection. The CLI should read the catalog, settings, and state using sensible defaults or explicit flags, then report available skillsets and current managed state.\n\nAcceptance criteria\n- The CLI provides a list command that shows skillset names and skill counts.\n- The CLI provides a verbose list mode that shows skills per skillset.\n- The CLI provides a status command that reports active managed skillsets and managed skill counts.\n- The status command indicates when manual skill settings are present without reimplementing Pi's full resource resolver.\n- The CLI supports flags for alternate settings, catalog, state, and skills root locations.\n- Python unit tests cover list, verbose list, status, defaults, and alternate path flags.\n\nBlocked by\nIssue 7","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:05:16Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:05:16Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-wqh","depends_on_id":"nixpkgs-kfl","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"_type":"issue","id":"nixpkgs-e1z","title":"feat(pi): add mutable settings and skillset state bootstrap","description":"What to build\nIntroduce mutable Pi settings behavior and skillset state bootstrapping so runtime skillset changes survive Home Manager rebuilds. The slice should initialize settings and state from Nix defaults when needed, preserve existing runtime state by default, and support an explicit reset path.\n\nAcceptance criteria\n- Pi settings can be managed in a mutable mode that creates or merges a real settings file instead of forcing an immutable replacement.\n- Runtime-owned fields used by skillset activation are preserved across rebuilds by default.\n- A skillset state file records generated patterns and active skillsets.\n- Default active skillsets are initialized when no state exists.\n- Existing state is preserved when it exists.\n- An explicit reset option restores the state to Nix defaults.\n- Activation behavior is covered by tests or reproducible smoke checks.\n\nBlocked by\nIssue 7","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:05:06Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:05:06Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-e1z","depends_on_id":"nixpkgs-kfl","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"_type":"issue","id":"nixpkgs-kfl","title":"feat(pi): deploy skills and catalog via Home Manager","description":"What to build\nWire the new Agent Skills Library into the Home Manager agent skill deployment path. Home Manager should use the m3ta-nixpkgs skill library as the canonical implementation, install the rendered skills directory for Pi and other tools, and publish the generated skill catalog for Pi runtime tooling.\n\nAcceptance criteria\n- Home Manager agent skill deployment no longer depends on AGENTS-provided skill composition logic.\n- The rendered skills directory is deployed to the shared agent skills location.\n- The generated catalog is deployed to the Pi skillsets location.\n- Existing external skill source options remain backwards-compatible while supporting new source options.\n- Home Manager evaluation tests or smoke tests prove a nested external skill fixture is deployed and cataloged.\n- Documentation or option descriptions identify m3ta-nixpkgs as the canonical skill composition provider.\n\nBlocked by\nIssues 5 and 6","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:04:55Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:04:55Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-kfl","depends_on_id":"nixpkgs-ir8","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"},{"issue_id":"nixpkgs-kfl","depends_on_id":"nixpkgs-nas","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":2,"dependent_count":4,"comment_count":0}
{"_type":"issue","id":"nixpkgs-nas","title":"feat(agent-skills): resolve skillsets in catalog","description":"What to build\nAdd skillset modeling and resolution to the Agent Skills catalog. The slice should allow global skillsets, source-wide default skillsets, and per-skill source mappings, then emit resolved skillset membership for each catalog skill while preserving skillset definitions for debugging.\n\nAcceptance criteria\n- Global skillsets can include skills by name or relative path.\n- Global skillsets can include categories by relative path prefix.\n- Global skillsets can exclude individual skills and category prefixes.\n- Source-wide default skillsets add membership to installed skills from that source.\n- Per-skill source mappings add membership only for final installed skills.\n- Skillset membership is merged additively.\n- Empty categories fail fast in phase 1.\n- Unknown or ambiguous skillset references fail fast.\n- The catalog includes both resolved membership per skill and the source skillset definitions.\n- Tests cover direct skill membership, category membership, excludes, source defaults, per-skill mappings, additive merge behavior, and validation failures.\n\nBlocked by\nIssue 5","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:04:49Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:04:49Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-nas","depends_on_id":"nixpkgs-ir8","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0}
{"_type":"issue","id":"nixpkgs-ir8","title":"feat(agent-skills): emit catalog v1 with provenance","description":"What to build\nGenerate the first version of the Agent Skills catalog as a machine-readable artifact alongside the rendered skills directory. The catalog should use portable relative paths, include source provenance, and act as the contract consumed by later skillset and runtime tooling.\n\nAcceptance criteria\n- The skill bundle produces a catalog artifact with schema version 1.\n- Catalog skills include skill name and relative target path.\n- Catalog skills do not require absolute runtime paths.\n- Catalog source provenance includes source label, skills directory, and original relative skill path.\n- External source labels are supported, with a stable fallback when no explicit label is provided.\n- Catalog generation is covered by fixture or golden-output tests.\n\nBlocked by\nIssues 1 and 3","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:04:46Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:04:46Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-ir8","depends_on_id":"nixpkgs-3m0","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"},{"issue_id":"nixpkgs-ir8","depends_on_id":"nixpkgs-5at","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":2,"dependent_count":2,"comment_count":0}
{"_type":"issue","id":"nixpkgs-vsp","title":"feat(agent-skills): validate custom and external collisions","description":"What to build\nMake the final skill bundle strict about conflicts across custom and external sources. The slice should discover custom skills recursively using the same rules as external sources and fail fast when the final catalog would contain duplicate skill names or duplicate target paths.\n\nAcceptance criteria\n- Custom skills are discovered recursively using the same terminal SKILL.md root rule as external skills.\n- Custom skills and external skills participate in the same final catalog validation.\n- Duplicate final skill names fail fast, including custom-versus-external duplicates.\n- Duplicate final target paths fail fast.\n- Positive tests verify custom and external skills can coexist.\n- Negative tests verify duplicate names and duplicate paths fail with clear diagnostics.\n\nBlocked by\nIssues 1 and 3","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:04:42Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:04:42Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-vsp","depends_on_id":"nixpkgs-3m0","type":"blocks","created_at":"2026-05-25T11:05:49Z","created_by":"m3tam3re","metadata":"{}"},{"issue_id":"nixpkgs-vsp","depends_on_id":"nixpkgs-5at","type":"blocks","created_at":"2026-05-25T11:05:48Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"nixpkgs-3m0","title":"feat(agent-skills): add source layouts and category validation","description":"What to build\nAdd per-source layout control to the Agent Skills Library so skill sources can be rendered in preserved, flat, or category-prefixed form. The slice should produce verifiable output paths for all three layouts and strictly validate category configuration.\n\nAcceptance criteria\n- The preserve layout keeps each skill root's relative source path under the target skills root.\n- The flat layout renders each skill under its skill name.\n- The under layout renders each skill under a validated category prefix while preserving the source structure below that prefix.\n- The default layout is preserve.\n- Category values are validated as safe relative paths.\n- A category is required for under layout.\n- Supplying a category with preserve or flat layout fails fast.\n- Fixture tests verify all layouts and invalid category combinations.\n\nBlocked by\nIssue 1","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:04:28Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:04:28Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-3m0","depends_on_id":"nixpkgs-5at","type":"blocks","created_at":"2026-05-25T11:05:48Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":1,"dependent_count":2,"comment_count":0}
{"_type":"issue","id":"nixpkgs-7vr","title":"feat(agent-skills): support select and exclude semantics","description":"What to build\nExtend the Agent Skills Library tracer so callers can include and exclude skills from each source predictably. The slice should support selecting skills by skill name or relative skill path, excluding skills by skill name or relative skill path, preserve the distinction between selecting all skills and selecting no skills, and fail fast when references are unknown or ambiguous.\n\nAcceptance criteria\n- selectSkills accepts both skill names and relative skill paths.\n- selectSkills set to null includes all discovered skills from a source.\n- selectSkills set to an empty list includes no skills from a source.\n- excludeSkills removes matching skills from a source and is validated against discovered source skills.\n- Unknown skill references fail with a clear error.\n- Ambiguous skill-name references fail with a clear error and require relative path disambiguation.\n- Fixture tests cover selection by name, selection by path, exclusion, unknown references, ambiguous references, null selection, and empty selection.\n\nBlocked by\nIssue 1","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:04:23Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:04:23Z","labels":["ready-for-agent"],"dependencies":[{"issue_id":"nixpkgs-7vr","depends_on_id":"nixpkgs-5at","type":"blocks","created_at":"2026-05-25T11:05:48Z","created_by":"m3tam3re","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"nixpkgs-5at","title":"feat(agent-skills): add recursive skill bundle tracer","description":"What to build\nCreate the first end-to-end tracer for the new m3ta-nixpkgs Agent Skills Library. The slice should expose the new skill bundle interface, provide a convenience interface for callers that only need the rendered skills directory, discover skill directories recursively, treat a directory containing SKILL.md as a terminal skill root, ignore hidden directories and dependency directories, derive skill names from parent directory names, and prove the resulting skill tree can be built from nested fixture sources.\n\nAcceptance criteria\n- A public agent-skills library interface exists for building a skill bundle and for retrieving only the rendered skills directory.\n- Nested skill directories containing SKILL.md are discovered and rendered into the output skill tree.\n- Discovery stops below a discovered skill root and does not treat nested content inside a skill as another skill.\n- Hidden directories and dependency directories are ignored during discovery.\n- Skill names are derived from the direct parent directory of SKILL.md.\n- Nix fixture tests or build/eval tests verify the tracer behavior end-to-end.\n\nBlocked by\nNone - can start immediately","status":"open","priority":2,"issue_type":"feature","owner":"p@m3ta.dev","created_at":"2026-05-25T09:04:14Z","created_by":"m3tam3re","updated_at":"2026-05-25T09:04:14Z","labels":["ready-for-agent"],"dependency_count":0,"dependent_count":4,"comment_count":0}
+7
View File
@@ -0,0 +1,7 @@
{
"database": "dolt",
"backend": "dolt",
"dolt_mode": "embedded",
"dolt_database": "nixpkgs",
"project_id": "b57a167a-6526-4211-a6c1-51686e431912"
}
+3
View File
@@ -0,0 +1,3 @@
# Use bd merge for beads JSONL files
.beads/issues.jsonl merge=beads
+526
View File
@@ -0,0 +1,526 @@
name: Update Nix Packages with nix-update
on:
schedule:
- cron: "0 2,14 * * *" # Every 12 hours at 2 AM and 2 PM
workflow_dispatch:
inputs:
package:
description: "Specific package to update (optional)"
required: false
type: string
concurrency:
group: nix-update-${{ github.ref }}
cancel-in-progress: true
env:
GIT_AUTHOR_NAME: "nix-update bot"
GIT_AUTHOR_EMAIL: "bot@m3ta.dev"
GIT_COMMITTER_NAME: "nix-update bot"
GIT_COMMITTER_EMAIL: "bot@m3ta.dev"
REPO_DIR: "/tmp/nixpkgs"
# Nix configuration
NIX_PATH: "nixpkgs=channel:nixos-unstable"
NIX_CONFIG: "experimental-features = nix-command flakes"
# Non-interactive mode
DEBIAN_FRONTEND: "noninteractive"
GIT_TERMINAL_PROMPT: "0"
jobs:
nix-update:
runs-on: nixos
timeout-minutes: 180
steps:
- name: Setup Environment and Authenticate
run: |
if [ -d "$REPO_DIR" ]; then rm -rf "$REPO_DIR"; fi
git config --global credential.helper store
echo "https://m3tam3re:${{ secrets.NIX_UPDATE_TOKEN }}@code.m3ta.dev" > ~/.git-credentials
chmod 600 ~/.git-credentials
git config --global user.name "$GIT_AUTHOR_NAME"
git config --global user.email "$GIT_AUTHOR_EMAIL"
git config --global init.defaultBranch master
- name: Checkout Repository
run: |
git clone --no-single-branch \
"https://m3tam3re@code.m3ta.dev/m3tam3re/nixpkgs.git" \
"$REPO_DIR"
- name: Update All Flake Inputs
id: update-flake-inputs
run: |
cd "$REPO_DIR"
echo "::group::Discovering version-pinned flake inputs"
# Get GitHub inputs with version refs (e.g., v1.2.9)
VERSIONED_INPUTS=$(nix flake metadata --json | jq -r '
.locks.nodes | to_entries[] |
select(.value.original.type == "github") |
select(.value.original.ref != null) |
select(.value.original.ref | test("^v?[0-9]+\\.[0-9]+")) |
"\(.key) \(.value.original.owner) \(.value.original.repo) \(.value.original.ref)"
')
echo "Discovered version-pinned inputs:"
echo "$VERSIONED_INPUTS"
echo "::endgroup::"
UPDATED_INPUTS=""
FAILED_INPUTS=""
# Update each version-pinned input
while read -r INPUT_NAME OWNER REPO CURRENT_REF; do
[ -z "$INPUT_NAME" ] && continue
echo "::group::Checking $INPUT_NAME ($OWNER/$REPO)"
# Get latest stable release (exclude prereleases)
# The /releases/latest endpoint already returns the latest non-prerelease, non-draft release
LATEST=$(curl -sf "https://api.github.com/repos/$OWNER/$REPO/releases/latest" | \
jq -r 'if .prerelease == false then .tag_name else empty end')
if [ -z "$LATEST" ]; then
echo "⚠️ No stable release found for $INPUT_NAME (repo may only have prereleases)"
FAILED_INPUTS="$FAILED_INPUTS $INPUT_NAME(no-stable-release)"
echo "::endgroup::"
continue
fi
echo "Current: $CURRENT_REF | Latest: $LATEST"
if [ "$LATEST" != "$CURRENT_REF" ]; then
echo "Updating $INPUT_NAME from $CURRENT_REF to $LATEST"
# Update flake.nix
sed -i "s|github:$OWNER/$REPO/[^\"']*|github:$OWNER/$REPO/$LATEST|g" flake.nix
# Update flake.lock for this input
if nix flake update "$INPUT_NAME" 2>&1 | tee /tmp/input-update.log; then
UPDATED_INPUTS="$UPDATED_INPUTS $INPUT_NAME($LATEST)"
echo "✅ Updated $INPUT_NAME to $LATEST"
else
echo "❌ Failed to update $INPUT_NAME"
FAILED_INPUTS="$FAILED_INPUTS $INPUT_NAME(update-failed)"
git checkout flake.nix flake.lock 2>/dev/null || true
fi
else
echo "✓ $INPUT_NAME is already up to date"
fi
echo "::endgroup::"
done <<< "$VERSIONED_INPUTS"
echo "::group::Updating non-version-pinned inputs"
# Update all non-version-pinned inputs (branches, no-ref)
nix flake update
echo "::endgroup::"
# Check if we have any changes
if [ -n "$(git status --porcelain flake.nix flake.lock)" ]; then
echo "::group::Committing flake input updates"
nix fmt flake.nix
git add flake.nix flake.lock
COMMIT_MSG="chore: update flake inputs"
[ -n "$UPDATED_INPUTS" ] && COMMIT_MSG="$COMMIT_MSG - $(echo $UPDATED_INPUTS | tr ' ' ', ')"
git commit -m "$COMMIT_MSG"
echo "flake_inputs_updated=true" >> $GITHUB_OUTPUT
echo "updated_inputs=${UPDATED_INPUTS# }" >> $GITHUB_OUTPUT
[ -n "$FAILED_INPUTS" ] && echo "failed_inputs=${FAILED_INPUTS# }" >> $GITHUB_OUTPUT
echo "::endgroup::"
else
echo "flake_inputs_updated=false" >> $GITHUB_OUTPUT
fi
- name: Check Prerequisites
id: check
run: |
cd "$REPO_DIR"
if [ ! -d "pkgs" ]; then
echo "❌ Error: 'pkgs' directory not found."
exit 1
fi
if [ -f "flake.nix" ]; then
echo "has_flake=true" >> $GITHUB_OUTPUT
else
echo "has_flake=false" >> $GITHUB_OUTPUT
fi
- name: Update Packages
id: update
run: |
cd "$REPO_DIR"
set -e
git checkout master
UPDATES_FOUND=false
UPDATED_PACKAGES=""
check_commit() {
[ "$1" != "$(git rev-parse HEAD)" ] && echo "true" || echo "false"
}
has_update_script() {
local pkg=$1
# Check if package has passthru.updateScript attribute
nix eval .#${pkg}.passthru.updateScript --json >/dev/null 2>&1
}
# Check if updateScript is a custom script (path-based) vs nix-update-script
is_custom_update_script() {
local pkg=$1
local result
# Custom scripts (./update.sh) become store paths ending in .sh
# nix-update-script produces a list with nix-update binary path
result=$(nix eval --impure --raw --expr "
let
flake = builtins.getFlake (toString ./.);
pkg = flake.packages.\${builtins.currentSystem}.${pkg};
script = pkg.passthru.updateScript or null;
in
if script == null then \"none\"
else if builtins.isPath script then \"custom\"
else if builtins.isString script then
(if builtins.match \".*\\.sh$\" script != null then \"custom\" else \"other\")
else if builtins.isList script then
let first = builtins.head script;
in if builtins.isString first && builtins.match \".*/nix-update$\" first != null
then \"nix-update-script\"
else \"custom\"
else if builtins.isAttrs script && script ? command then \"custom\"
else \"other\"
" 2>/dev/null || echo "other")
[[ "$result" == "custom" ]]
}
# Run a custom update script directly
# Scripts must use nix-shell shebang for their own dependencies
run_custom_update_script() {
local pkg=$1
local before_hash=$(git rev-parse HEAD)
echo " 🔧 Detected custom update script for $pkg"
# Resolve the store path of the update script
local script_path
script_path=$(nix eval --impure --raw --expr "
let
flake = builtins.getFlake (toString ./.);
pkg = flake.packages.\${builtins.currentSystem}.${pkg};
script = pkg.passthru.updateScript;
cmd = if builtins.isAttrs script then script.command
else if builtins.isList script then builtins.head script
else script;
in toString cmd
" 2>/dev/null)
if [ -z "$script_path" ]; then
echo "❌ Could not resolve update script path for $pkg"
return 1
fi
# Set environment variables that nix-update would normally provide
export UPDATE_NIX_NAME=$(nix eval --raw .#${pkg}.name 2>/dev/null || echo "$pkg")
export UPDATE_NIX_PNAME=$(nix eval --raw .#${pkg}.pname 2>/dev/null || echo "$pkg")
export UPDATE_NIX_OLD_VERSION=$(nix eval --raw .#${pkg}.version 2>/dev/null || echo "unknown")
export UPDATE_NIX_ATTR_PATH="$pkg"
echo " Running: $script_path"
if bash "$script_path" 2>&1 | tee /tmp/update-${pkg}.log; then
if [ "$(check_commit "$before_hash")" = "true" ]; then
echo "✅ Updated $pkg (via custom script)"
return 0
fi
# Script succeeded but no commit — may already be up to date
if grep -q "already at latest\|nothing to do" /tmp/update-${pkg}.log; then
echo "✓ $pkg already up to date"
return 1
fi
fi
# Clean up on failure
git checkout -- . 2>/dev/null || true
git clean -fd 2>/dev/null || true
if ! grep -q "already at latest\|nothing to do\|No new version found" /tmp/update-${pkg}.log; then
echo "⚠️ Custom update script failed for $pkg"
fi
return 1
}
run_update() {
local pkg=$1
local before_hash=$(git rev-parse HEAD)
echo "::group::Updating $pkg"
# Check if this package has a custom update script
if is_custom_update_script "$pkg"; then
if run_custom_update_script "$pkg"; then
echo "::endgroup::"
return 0
else
echo "::endgroup::"
return 1
fi
fi
# Standard nix-update for packages with nix-update-script
local args=("--flake" "--commit" "--use-github-releases")
args+=("$pkg")
if nix-update "${args[@]}" 2>&1 | tee /tmp/update-${pkg}.log; then
if [ "$(check_commit "$before_hash")" = "true" ]; then
echo "✅ Updated $pkg"
echo "::endgroup::"
return 0
fi
fi
# Clean up any uncommitted changes from failed update
git checkout -- . 2>/dev/null || true
git clean -fd 2>/dev/null || true
echo "::endgroup::"
if ! grep -q "already up to date\|No new version found" /tmp/update-${pkg}.log; then
echo "⚠️ Update failed for $pkg"
fi
return 1
}
if [ -n "${{ inputs.package }}" ]; then
pkg="${{ inputs.package }}"
if [ -d "pkgs/$pkg" ]; then
if run_update "$pkg"; then
UPDATES_FOUND=true
UPDATED_PACKAGES="$pkg"
fi
else
echo "❌ Package 'pkgs/$pkg' not found"
fi
else
# Dynamically discover packages with updateScript attribute
echo "🔍 Discovering packages with passthru.updateScript..."
# Get all packages and filter those with updateScript
ALL_PACKAGES=$(find pkgs -mindepth 1 -maxdepth 1 -type d -exec basename {} \; 2>/dev/null | sort)
UPDATABLE_PACKAGES=""
if [ -z "$ALL_PACKAGES" ]; then
echo "No packages found in pkgs/"
exit 0
fi
for pkg in $ALL_PACKAGES; do
if has_update_script "$pkg"; then
echo " ✓ $pkg (has updateScript)"
UPDATABLE_PACKAGES="$UPDATABLE_PACKAGES $pkg"
else
echo " ⊘ $pkg (no updateScript - skipping)"
fi
done
if [ -z "$UPDATABLE_PACKAGES" ]; then
echo "️ No packages with updateScript found."
exit 0
fi
echo ""
echo "📦 Found $(echo $UPDATABLE_PACKAGES | wc -w) updatable packages"
echo ""
for pkg in $UPDATABLE_PACKAGES; do
if run_update "$pkg"; then
UPDATES_FOUND=true
if [ -n "$UPDATED_PACKAGES" ]; then
UPDATED_PACKAGES="$UPDATED_PACKAGES, $pkg"
else
UPDATED_PACKAGES="$pkg"
fi
fi
done
fi
COMMIT_COUNT=$(git rev-list --count origin/master..HEAD)
if [ "$COMMIT_COUNT" -gt 0 ]; then
echo "✅ $COMMIT_COUNT updates committed locally."
echo "has_updates=true" >> $GITHUB_OUTPUT
echo "updated_packages=${UPDATED_PACKAGES}" >> $GITHUB_OUTPUT
else
echo "️ No updates found."
echo "has_updates=false" >> $GITHUB_OUTPUT
fi
- name: Verify Builds
if: steps.update.outputs.has_updates == 'true' || steps.update-flake-inputs.outputs.flake_inputs_updated == 'true'
run: |
cd "$REPO_DIR"
echo "::group::Running flake check"
if ! nix flake check; then
echo "❌ Flake check failed"
exit 1
fi
echo "✅ Flake check passed"
echo "::endgroup::"
IFS=', ' read -ra PKGS <<< "${{ steps.update.outputs.updated_packages }}"
FAILED_PACKAGES=()
SUCCESSFUL_PACKAGES=()
for pkg in "${PKGS[@]}"; do
echo "::group::Building $pkg"
if nix build .#$pkg 2>&1 | tee /tmp/build-${pkg}.log; then
echo "✅ Build successful for $pkg"
SUCCESSFUL_PACKAGES+=("$pkg")
else
echo "❌ Build failed for $pkg"
FAILED_PACKAGES+=("$pkg")
fi
echo "::endgroup::"
done
if [ ${#FAILED_PACKAGES[@]} -gt 0 ]; then
echo ""
echo "❌ Failed packages: ${FAILED_PACKAGES[*]}"
echo "✅ Successful packages: ${SUCCESSFUL_PACKAGES[*]}"
echo ""
# Upload logs as artifacts for debugging
echo "## Build Failure Logs" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
for pkg in "${FAILED_PACKAGES[@]}"; do
echo "### $pkg" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
cat /tmp/build-${pkg}.log >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
done
exit 1
fi
echo ""
echo "✅ All packages built successfully: ${SUCCESSFUL_PACKAGES[*]}"
- name: Push Changes
if: steps.update.outputs.has_updates == 'true' || steps.update-flake-inputs.outputs.flake_inputs_updated == 'true'
run: |
cd "$REPO_DIR"
PACKAGES="${{ steps.update.outputs.updated_packages }}"
if [ "${{ steps.update-flake-inputs.outputs.flake_inputs_updated }}" = "true" ]; then
UPDATED_INPUTS="${{ steps.update-flake-inputs.outputs.updated_inputs }}"
if [ -n "$PACKAGES" ]; then
PACKAGES="$PACKAGES, flake inputs ($UPDATED_INPUTS)"
else
PACKAGES="flake inputs ($UPDATED_INPUTS)"
fi
fi
echo "::group::Git Operations"
echo "Current commit: $(git rev-parse HEAD)"
echo "Pending commits: $(git rev-list --count origin/master..HEAD)"
echo ""
echo "Pulling latest changes (rebase)..."
if git pull --rebase origin master; then
echo "✅ Rebase successful"
else
echo "⚠️ Rebase failed, resetting and retrying..."
git rebase --abort 2>/dev/null || true
git reset --hard origin/master
echo "❌ Could not rebase, updates lost. Will retry next run."
exit 0
fi
echo ""
echo "Pushing changes to master..."
git push origin master
echo ""
echo "✅ Successfully pushed updates for: $PACKAGES"
echo "::endgroup::"
- name: Cleanup
if: always()
run: |
# Remove git credentials securely
rm -f ~/.git-credentials
git config --global --unset credential.helper 2>/dev/null || true
# Remove temporary directory
rm -rf "$REPO_DIR"
# Remove all log files
rm -f /tmp/update-*.log /tmp/build-*.log /tmp/opencode-build.log /tmp/update-log.txt /tmp/success-packages.txt
# Clear sensitive environment variables
unset GIT_AUTHOR_EMAIL GIT_COMMITTER_EMAIL
- name: Summary
if: always()
run: |
HAS_UPDATES="false"
if [ "${{ steps.update.outputs.has_updates }}" = "true" ]; then
HAS_UPDATES="true"
echo "# ✅ Update Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Updated Packages" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "\`${{ steps.update.outputs.updated_packages }}\`" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ steps.update-flake-inputs.outputs.flake_inputs_updated }}" = "true" ]; then
HAS_UPDATES="true"
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Updated Flake Inputs" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
UPDATED_INPUTS="${{ steps.update-flake-inputs.outputs.updated_inputs }}"
if [ -n "$UPDATED_INPUTS" ]; then
echo "$UPDATED_INPUTS" | tr ' ' '\n' | while read -r input; do
[ -n "$input" ] && echo "- **$input**" >> $GITHUB_STEP_SUMMARY
done
fi
FAILED_INPUTS="${{ steps.update-flake-inputs.outputs.failed_inputs }}"
if [ -n "$FAILED_INPUTS" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Failed Inputs" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "$FAILED_INPUTS" | tr ' ' '\n' | while read -r input; do
[ -n "$input" ] && echo "- $input" >> $GITHUB_STEP_SUMMARY
done
fi
fi
if [ "$HAS_UPDATES" = "true" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Status" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- ✅ All updates validated with \`nix flake check\`" >> $GITHUB_STEP_SUMMARY
echo "- ✅ All builds successful" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Changes pushed to master" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Workflow Performance" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- Started: ${{ github.event.head_commit.timestamp }}" >> $GITHUB_STEP_SUMMARY
echo "- Completed: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
echo "- Workflow Run: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
else
echo "# ️ No Updates Required" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "No updates found this run. All packages and flake inputs are up to date." >> $GITHUB_STEP_SUMMARY
fi
+52
View File
@@ -0,0 +1,52 @@
# Nix build outputs
result
result-*
# Direnv
.direnv/
.envrc
# Development shells
shell.nix
# Editor files
.vscode/
.idea/
*.swp
*.swo
*~
.DS_Store
# Nix-specific
.pre-commit-config.yaml
.envrc.local
# Temporary files
*.tmp
*.log
# Testing
test-result/
# Local configuration (if you want to keep local overrides)
local.nix
flake.lock.bak
.todos/
# AI agent state
.sidecar/
.sidecar-*
.sisyphus/
.sidecar-agent
.sidecar-task
.sidecar-pr
.sidecar-start.sh
.sidecar-base
.td-root
.cache
.pi*
# Beads / Dolt files (added by bd init)
.dolt/
*.db
.beads-credential-key
+84
View File
@@ -0,0 +1,84 @@
# Agent Instructions
This project uses **bd** (beads) for issue tracking. Run `bd prime` for full workflow context.
## Quick Reference
```bash
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --claim # Claim work atomically
bd close <id> # Complete work
bd dolt push # Push beads data to remote
```
## Non-Interactive Shell Commands
**ALWAYS use non-interactive flags** with file operations to avoid hanging on confirmation prompts.
Shell commands like `cp`, `mv`, and `rm` may be aliased to include `-i` (interactive) mode on some systems, causing the agent to hang indefinitely waiting for y/n input.
**Use these forms instead:**
```bash
# Force overwrite without prompting
cp -f source dest # NOT: cp source dest
mv -f source dest # NOT: mv source dest
rm -f file # NOT: rm file
# For recursive operations
rm -rf directory # NOT: rm -r directory
cp -rf source dest # NOT: cp -r source dest
```
**Other commands that may prompt:**
- `scp` - use `-o BatchMode=yes` for non-interactive
- `ssh` - use `-o BatchMode=yes` to fail instead of prompting
- `apt-get` - use `-y` flag
- `brew` - use `HOMEBREW_NO_AUTO_UPDATE=1` env var
<!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:ca08a54f -->
## Beads Issue Tracker
This project uses **bd (beads)** for issue tracking. Run `bd prime` to see full workflow context and commands.
### Quick Reference
```bash
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --claim # Claim work
bd close <id> # Complete work
```
### Rules
- Use `bd` for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists
- Run `bd prime` for detailed command reference and session close protocol
- Use `bd remember` for persistent knowledge — do NOT use MEMORY.md files
## Session Completion
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
**MANDATORY WORKFLOW:**
1. **File issues for remaining work** - Create issues for anything that needs follow-up
2. **Run quality gates** (if code changed) - Tests, linters, builds
3. **Update issue status** - Close finished work, update in-progress items
4. **PUSH TO REMOTE** - This is MANDATORY:
```bash
git pull --rebase
bd dolt push
git push
git status # MUST show "up to date with origin"
```
5. **Clean up** - Clear stashes, prune remote branches
6. **Verify** - All changes committed AND pushed
7. **Hand off** - Provide context for next session
**CRITICAL RULES:**
- Work is NOT complete until `git push` succeeds
- NEVER stop before pushing - that leaves work stranded locally
- NEVER say "ready to push when you are" - YOU must push
- If push fails, resolve and retry until it succeeds
<!-- END BEADS INTEGRATION -->
+111
View File
@@ -0,0 +1,111 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/).
## [Unreleased]
### Fixed
- `openwork` 0.17.30: upstream renamed desktop/icon assets from `@openworkdesktop.{desktop,png}` to `openwork.{desktop,png}` and dropped the `Icon=`/`--no-sandbox` substitutions that are no longer needed
### Changed
- Remove duplicate opencode-rules.nix (backward-compat alias preserved)
- Tool-agnostic naming in coding-rules lib internals
- Remove redundant overlay entries for non-existent flake inputs
- Remove redundant 'additions' overlay (identical to 'default')
### Removed
- Dead overlay entries for non-existent flake inputs
- Legacy `mkOpencodeRules` alias and `lib.opencode-rules` backward-compat entry (use `mkCodingRules` / `lib.coding-rules`)
## [0.4.0] - 2026-04-15
### Added
- Pi-agent wrapper with systemd sandbox and per-host-user policy
- Containerized Pi agent
- `lib.agents.nix` with loadCanonical, renderers (OpenCode, Claude Code, Pi), and shellHook
- `lib.coding-rules` helper for per-project rule injection (renamed from opencode-rules)
- Home Manager modules for coding agents: `claude-code`, `opencode`, `pi`
- Agents rework with canonical TOML format and harness-agnostic renderers
- `vibetyper` and `eigent` packages
- `openspec` package
- `basecamp-cli` package
- `openshell` package (0.0.14 through 0.0.23)
- `openwork` package
- Opencode config moved into m3ta-nixpkgs
- Opencode dev shell with mkCodingRules demo
### Changed
- OpenCode flake input updated through v1.1.65 to v1.3.6
- Switched from local opencode package to upstream flake input
- Removed opencode-desktop (awaiting upstream fix), later re-enabled
- Nix eval warnings resolved
- Flake inputs updated throughout
### Fixed
- Pi settings sync
- Remove openwork sidecars in preFixup to prevent .opencode-wrapped conflict
- Remove sidecar binaries from openwork $out/bin to fix buildEnv conflict
- Vibetyper .desktop entry
- Opencode module formatting
- Formatting opencode module
## [0.3.0] - 2026-02-20
### Added
- `notesmd-cli` package with flake checks
- `sidecar` and `td` packages
- `opencode-desktop` package with Wayland support
- `mem0` package (1.0.2 through 1.0.9)
- `kestracli` / `kestractl` package (1.0.0 to 1.2.2)
### Changed
- Nix-update CI workflow optimized with caching and parallel processing
- Restructured n8n version handling for nix-update compatibility
- Switched formatter from nixpkgs-fmt to alejandra
- Replace local opencode with upstream flake input v1.1.27
### Fixed
- n8n build error
- n8n pnpm hash
- n8n update script
- Gitea runner opencode.url flake input
- nix-update workflow: YAML syntax, jobs indentation, PR body formatting
- Arithmetic increment failing with set -e in nix-update workflow
- Removed magic-nix-cache-action causing platform mapping error
- Opencode bun version requirement patched to match upstream lockfile
- Deprecated opencode update logic removed
- nix fmt without arg in workflow
- Extra Lua config renamed initLua
- Stt-ptt use pkill for better process management
## [0.2.0] - 2026-01-13
### Added
- Gitea Actions workflow for automated package updates with nix-update
- `n8n`, `beads`, and `opencode` packages
- `stt-ptt` package with auto-language detection
- `rofi-project-opener` for rofi-based project launching
- Hierarchical AGENTS.md knowledge base
- Dev shell structure with python and devops shells
- Port management modules (NixOS + Home Manager)
- Port helper library (`lib/ports.nix`)
### Changed
- Beads updated through v0.49.1
- N8n updated through v2.8.1
- Opencode updated through v1.1.18
- Documentation expanded with comprehensive patterns and HM module docs
### Fixed
- Python env version fix for marimo
## [0.1.0] - 2025-10-04
### Added
- Initial flake setup with packages, overlays, modules, and shells
- NixOS and Home Manager module infrastructure
- `lib/` shared utilities
- `overlays/mods/` for package modifications
- `templates/` for new packages/modules
- `examples/` for usage documentation
-7
View File
@@ -1,7 +0,0 @@
This repository is being used as a Dolt remote.
ref=refs/dolt/data
head=43d141bca1faebdf2ed20deb3c147ca1b2946eea
timestamp=2026-07-04T07:30:30Z
+82
View File
@@ -0,0 +1,82 @@
# m3ta-nixpkgs
Personal Nix flake repository: custom packages, overlays, NixOS modules, and Home Manager modules.
## Features
- 🎁 **Custom Packages**: Collection of personal Nix packages
- 🔄 **Overlays**: Package modifications and enhancements
- 🐚 **Development Shells**: Pre-configured environments (Python, DevOps)
- ⚙️ **NixOS Modules**: System-level configuration modules
- 🏠 **Home Manager Modules**: User-level configuration modules
- 📚 **Library Functions**: Helper utilities for configuration management
- ❄️ **Flakes Only**: Modern Nix flakes support (no channels)
## Quick Links
- 📖 [Full Documentation](./docs)
- 🚀 [Quick Start Guide](./docs/QUICKSTART.md)
- 📚 [Architecture](./docs/ARCHITECTURE.md)
- 🤝 [Contributing](./docs/CONTRIBUTING.md)
- 📦 [Packages](./docs/packages/)
- ⚙️ [Modules](./docs/modules/)
- 📖 [Guides](./docs/guides/)
## Quick Start
```bash
# Add to your flake
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
# Build a package
nix build git+https://code.m3ta.dev/m3tam3re/nixpkgs#code2prompt
# Run a package
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#zellij-ps
```
## Available Packages
See [📦 Packages](./docs/packages/) for the full index with descriptions.
Quick reference — build any package directly:
```bash
nix build git+https://code.m3ta.dev/m3tam3re/nixpkgs#<package-name>
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#<package-name>
```
Notable packages: `sidecar`, `td`, `code2prompt`, `mem0`, `n8n`, `zellij-ps`.
## Automated Package Updates
This repository uses Gitea Actions to automatically update packages using `nix-update`:
**Workflow**: [`.gitea/workflows/nix-update.yml`](./.gitea/workflows/nix-update.yml)
**Schedule**: Runs weekly on Sundays, and can be triggered manually.
**What it does**:
- Checks all packages in `pkgs/` for updates
- Updates versions and hashes using `nix-update --flake --commit`
- Creates a new branch with updates
- Opens a pull request automatically
**Manual Trigger**:
Go to **Actions → Update Nix Packages with nix-update → Run workflow** in Gitea UI, then optionally specify a specific package to update.
**Setup Required**:
1. Create a Personal Access Token in Gitea (Settings → Applications → Generate Token)
2. Token scopes needed: `user`, `repo`, `write:issue`
3. Add token as secret: Settings → Secrets → New → `NIX_UPDATE_TOKEN`
For detailed usage, module documentation, package references, and contribution guidelines, see the [full documentation](./docs).
## License
Individual packages may have their own licenses. Check each package's `meta.license` attribute.
## Maintainer
[@m3tam3re](https://m3ta.dev)
+473
View File
@@ -0,0 +1,473 @@
# Architecture
Understanding the design and structure of m3ta-nixpkgs.
## Overview
m3ta-nixpkgs is organized as a modern Nix flake with a focus on reusability, consistency, and maintainability. The repository follows clear conventions and patterns to make it easy to understand, extend, and contribute to.
## Repository Structure
```
m3ta-nixpkgs/
├── flake.nix # Main entry point, defines all outputs
├── pkgs/ # Custom packages (callPackage registry)
│ ├── default.nix # Package registry (entry point)
│ ├── code2prompt/ # Individual packages
│ ├── hyprpaper-random/
│ ├── mem0/
│ └── ...
├── modules/
│ ├── nixos/ # NixOS modules
│ │ ├── default.nix # Module aggregator
│ │ ├── mem0.nix
│ │ └── ports.nix
│ └── home-manager/ # Home Manager modules
│ ├── default.nix # Module aggregator
│ ├── ports.nix
│ ├── cli/ # Categorized modules
│ │ ├── default.nix
│ │ └── zellij-ps.nix
│ └── coding/
│ ├── default.nix
│ └── editors.nix
├── lib/ # Shared utilities
│ ├── default.nix # Library aggregator
│ └── ports.nix # Port management functions
├── shells/ # Development environments
│ ├── default.nix # Shell registry
│ ├── python.nix
│ └── devops.nix
├── overlays/ # Package modifications
│ ├── default.nix # Overlay aggregator
│ └── mods/
│ └── default.nix # Individual overlays
├── templates/ # Boilerplate for new items
│ ├── package/
│ ├── nixos-module/
│ └── home-manager-module/
├── examples/ # Usage examples
│ ├── nixos-configuration.nix
│ └── home-manager-standalone.nix
└── docs/ # Documentation
```
## Flake Outputs
`flake.nix` is the entry point that defines all outputs:
### Packages
```nix
packages = forAllSystems (system: let
pkgs = pkgsFor system;
in
import ./pkgs {inherit pkgs;});
```
- Built for all supported systems
- Uses `callPackage` pattern for lazy evaluation
- Available via `nix build .#<package-name>`
### Overlays
```nix
overlays = {
# Default overlay: adds all custom packages
default = final: prev: import ./pkgs {pkgs = final;};
# Additions overlay: same as default
additions = final: prev: import ./pkgs {pkgs = final;};
# Modifications overlay: modifies existing nixpkgs packages
modifications = final: prev: import ./overlays/mods {inherit prev;};
};
```
- `default`: Adds all custom packages to nixpkgs
- `additions`: Individual package additions
- `modifications`: Overrides existing packages
### NixOS Modules
```nix
nixosModules = {
default = ./modules/nixos; # Import all modules
ports = ./modules/nixos/ports.nix; # Specific module
mem0 = ./modules/nixos/mem0.nix;
};
```
- System-level configuration modules
- Use `m3ta.*` namespace
- Can import all modules or individual ones
### Home Manager Modules
```nix
homeManagerModules = {
default = import ./modules/home-manager;
ports = import ./modules/home-manager/ports.nix;
zellij-ps = import ./modules/home-manager/zellij-ps.nix;
};
```
- User-level configuration modules
- Categorized by function (cli, coding)
- Use `m3ta.*` namespace
### Library Functions
```nix
lib = forAllSystems (system: let
pkgs = pkgsFor system;
in
import ./lib {lib = pkgs.lib;});
```
- Helper functions for configuration
- Port management utilities
- Can be used in your configurations
### Development Shells
```nix
devShells = forAllSystems (system: let
pkgs = pkgsFor system;
in
import ./shells {inherit pkgs;});
```
- Pre-configured development environments
- Available: `default`, `python`, `devops`
- Usage: `nix develop .#<shell-name>`
### Templates
```nix
templates = {
package = {
path = ./templates/package;
description = "Template for a new package";
};
nixos-module = {
path = ./templates/nixos-module;
description = "Template for a new NixOS module";
};
home-manager-module = {
path = ./templates/home-manager-module;
description = "Template for a new Home Manager module";
};
};
```
- Boilerplate for quick start
- Usage: `nix flake init -t .#template-name`
## Package Organization
### Registry Pattern
`pkgs/default.nix` acts as a central registry:
```nix
{
inherit (pkgs) callPackage;
} rec {
code2prompt = callPackage ./code2prompt {};
hyprpaper-random = callPackage ./hyprpaper-random {};
mem0 = callPackage ./mem0 {};
# ...
}
```
**Benefits**:
- Lazy evaluation: only builds requested packages
- Consistent interface: all packages use `callPackage`
- Easy discovery: one file lists all packages
### Package Structure
Each package lives in its own directory:
```
pkgs/your-package/
├── default.nix # Package definition
├── source.py # Optional: source files
└── README.md # Optional: package documentation
```
**Conventions**:
- Directory name matches registry attribute
- Use `callPackage` for dependencies
- Always include `meta` with all fields
### Common Package Patterns
#### Rust Packages
```nix
rustPlatform.buildRustPackage rec {
pname = "myapp";
version = "1.0.0";
src = fetchFromGitHub { ... };
cargoLock.lockFile = src + "/Cargo.lock";
# ...
}
```
#### Python Packages
```nix
python3.pkgs.buildPythonPackage rec {
pname = "mypythonapp";
version = "1.0.0";
src = fetchFromGitHub { ... };
dependencies = with python3.pkgs; [requests click];
# ...
}
```
#### Shell Scripts
```nix
writeShellScriptBin "myscript" ''
#!/usr/bin/env bash
echo "Hello World"
''
```
#### AppImage
```nix
appimageTools.wrapType2 rec {
name = "myapp";
src = fetchurl { ... };
# ...
}
```
## Module Organization
### NixOS Modules
Located in `modules/nixos/`:
```
modules/nixos/
├── default.nix # Imports all modules
├── ports.nix # Port management
├── mem0.nx # Individual module
```
**Pattern**:
```nix
{config, lib, pkgs, ...}:
with lib; let
cfg = config.m3ta.myModule;
in {
options.m3ta.myModule = {
enable = mkEnableOption "description";
# ... options
};
config = mkIf cfg.enable {
# ... configuration
};
}
```
### Home Manager Modules
Located in `modules/home-manager/` with categories:
```
modules/home-manager/
├── default.nix # Imports all modules
├── ports.nix # Port management
├── cli/
│ ├── default.nix # Aggregates CLI modules
│ └── zellij-ps.nix
└── coding/
├── default.nix # Aggregates coding modules
└── editors.nix
```
**Categories**:
- `cli/`: Command-line tools and utilities
- `coding/`: Development tools and editors
**Pattern** (same as NixOS):
```nix
{config, lib, pkgs, ...}:
with lib; let
cfg = config.m3ta.coding.editors;
in {
options.m3ta.coding.editors = {
enable = mkEnableOption "editor configuration";
# ... options
};
config = mkIf cfg.enable {
# ... configuration
};
}
```
## Library Functions
Located in `lib/`:
```nix
{lib}: {
# Port management utilities
ports = import ./ports.nix {inherit lib;};
}
```
### Port Management
Centralized port management across hosts:
```nix
# Usage in configuration
portHelpers = inputs.m3ta-nixpkgs.lib.${system}.ports.mkPortHelpers myPorts;
# Get port with host override
services.nginx.port = portHelpers.getPort "nginx" "laptop";
# Get all ports for host
allLaptopPorts = portHelpers.getHostPorts "laptop";
```
**Benefits**:
- Single source of truth for ports
- Host-specific overrides
- Avoid port conflicts
## Naming Conventions
| Context | Convention | Example |
|---------|------------|---------|
| Packages | `lowercase-hyphen` | `hyprpaper-random` |
| Variables | `camelCase` | `portHelpers` |
| Module options | `m3ta.*` | `m3ta.ports.enable` |
| Files | `lowercase-hyphen` | `my-module.nix` |
| Directories | `lowercase-hyphen` | `cli/`, `coding/` |
## Code Patterns
### Module Options
Always use `mkEnableOption` for enable flags:
```nix
options.m3ta.myModule = {
enable = mkEnableOption "description";
};
```
### Conditional Configuration
Use `mkIf` for conditional config:
```nix
config = mkIf cfg.enable {
# Only applied when cfg.enable is true
};
```
### Multiple Conditions
Use `mkMerge` for multiple conditions:
```nix
config = mkMerge [
(mkIf cfg.feature1.enable { ... })
(mkIf cfg.feature2.enable { ... })
];
```
### Imports
Multi-line, trailing commas:
```nix
{
lib,
stdenv,
fetchFromGitHub,
}:
```
### Meta Fields
Always include all fields:
```nix
meta = with lib; {
description = "...";
homepage = "...";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "program-name";
};
```
## Design Decisions
### Flakes-Only
**Decision**: Use flakes exclusively, no channels.
**Rationale**:
- Reproducible builds
- Explicit dependencies
- Better integration with modern Nix tooling
### CallPackage Pattern
**Decision**: Use `callPackage` for all packages.
**Rationale**:
- Lazy evaluation
- Clear dependency graph
- Consistent interface
### Module Categorization
**Decision**: Categorize Home Manager modules by function.
**Rationale**:
- Easier to find related modules
- Logical organization
- Follows user mental model
### Port Management
**Decision**: Centralized port management with host overrides.
**Rationale**:
- Avoid port conflicts
- Easy to manage multiple hosts
- Single source of truth
### Namespace Convention
**Decision**: Use `m3ta.*` namespace for all modules.
**Rationale**:
- Avoid conflicts
- Clear attribution
- Easy to discover
## Supported Systems
- `x86_64-linux` - Primary development target
- `aarch64-linux` - ARM Linux
- `x86_64-darwin` - macOS Intel
- `aarch64-darwin` - macOS Apple Silicon
**Note**: Some packages may be Linux-only (check `meta.platforms`).
+373
View File
@@ -0,0 +1,373 @@
# Contributing
Contributing to m3ta-nixpkgs.
## Setting Up Development Environment
```bash
# Clone repository
git clone https://code.m3ta.dev/m3tam3re/nixpkgs.git
cd nixpkgs
# Enter development shell (includes linting tools)
nix develop
# Or use a specific shell
nix develop .#python
nix develop .#devops
```
## Code Style and Formatting
### Formatting
Use alejandra to format Nix files:
```bash
# Format all files
nix fmt
# Format specific file
alejandra path/to/file.nix
```
**Always run `nix fmt` before committing.**
### Linting
Linting tools are only available inside the dev shell:
```bash
# Enter dev shell first
nix develop
# Run statix (linter)
statix check .
# Run deadnix (find dead code)
deadnix .
```
## Conventions
### Naming
- **Packages**: `lowercase-hyphen` (e.g., `hyprpaper-random`)
- **Variables**: `camelCase` (e.g., `portHelpers`)
- **Module options**: `m3ta.*` namespace
- **Files**: `lowercase-hyphen` (e.g., `my-module.nix`)
### Imports
Multi-line, trailing commas:
```nix
{
lib,
stdenv,
fetchFromGitHub,
}:
```
### Meta Fields
Always include all fields in package definitions:
```nix
meta = with lib; {
description = "Short description";
homepage = "https://github.com/author/repo";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "program-name";
};
```
### Module Pattern
Standard module pattern:
```nix
{ config, lib, pkgs, ... }:
with lib; let
cfg = config.m3ta.myModule;
in {
options.m3ta.myModule = {
enable = mkEnableOption "description";
};
config = mkIf cfg.enable {
# Configuration
};
}
```
## Adding a Package
1. Create package directory in `pkgs/your-package/`
2. Write `default.nix` with package definition
3. Register in `pkgs/default.nix`
See [Adding Packages Guide](./guides/adding-packages.md) for detailed instructions.
**Note**: Package versions are automatically updated weekly via Gitea Actions using `nix-update`. You don't need to worry about keeping versions current - the automation will create PRs for updates. Just focus on ensuring the package builds and works correctly.
### Package Testing
```bash
# Build the package
nix build .#your-package
# Test if package runs
nix run .#your-package -- --help
# Check with linter
nix develop
statix check pkgs/your-package/
```
## Adding a NixOS Module
1. Create module file in `modules/nixos/your-module.nix`
2. Import in `modules/nixos/default.nix` (or use directly)
```nix
# modules/nixos/default.nix
{
imports = [
./your-module.nix
./other-module.nix
];
}
```
## Adding a Home Manager Module
1. Choose appropriate category: `cli/`, `coding/`, or root
2. Create module file
3. Import in category's `default.nix` or root `default.nix`
```nix
# modules/home-manager/cli/default.nix
{
imports = [
./your-tool.nix
];
}
```
## Development Workflow
### Making Changes
```bash
# Create feature branch
git checkout -b feature/your-change
# Make changes
# Format code
nix fmt
# Test builds
nix build .#your-package
nix flake check
# Lint
nix develop
statix check .
deadnix .
```
### Commit Format
Use conventional commits:
```
type: brief description
Types:
- feat: New feature
- fix: Bug fix
- docs: Documentation changes
- style: Code style changes (formatting)
- refactor: Code refactoring
- chore: Maintenance tasks
- test: Adding or updating tests
```
Examples:
```
feat: add new package for myapp
fix: resolve port conflict in mem0 module
docs: update installation instructions
style: format nix files
refactor: simplify port management
chore: update dependencies
```
### Before Committing
```bash
# Format all files
nix fmt
# Validate flake
nix flake check
# Run linters
nix develop
statix check .
deadnix .
# Add files
git add .
# Commit
git commit -m "type: description"
```
## Testing
### Package Testing
```bash
# Build for specific system
nix build .#your-package --system x86_64-linux
# Test on different systems
nix build .#your-package --system aarch64-linux
```
### Module Testing
```bash
# Test NixOS configuration
sudo nixos-rebuild test --flake .#hostname
# Test Home Manager configuration
home-manager switch --flake .#username@hostname
```
### Flake Validation
```bash
# Validate all outputs
nix flake check
# Show all outputs
nix flake show
```
## Pull Requests
### Before Submitting
1. [ ] Code formatted with `nix fmt`
2. [ ] Passes `statix check .`
3. [ ] Passes `deadnix .`
4. [ ] Passes `nix flake check`
5. [ ] New packages include `meta` fields
6. [ ] Documentation updated if needed
7. [ ] Commit messages follow convention
### Handling Automated Update PRs
The repository has automated package updates via Gitea Actions (see main README for details). When reviewing automated update PRs:
1. **Build and test**: Verify the updated package builds successfully
2. **Check changelinks**: Review upstream release notes for breaking changes
3. **Test functionality**: Ensure the package still works as expected
4. **Review package definition**: Check if any manual adjustments are needed
For urgent updates, you can manually trigger the workflow from the Gitea UI or update the package manually.
### PR Description
Include:
- What changed and why
- How to test
- Any breaking changes
- Related issues
## Troubleshooting
### Hash Errors
When building packages, you may encounter hash errors:
```
got: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
expected: sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=
```
**Solution**: Copy the `got` hash and update the package:
```nix
src = fetchFromGitHub {
# ...
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Use actual hash
};
```
### Dependency Not Found
If a package isn't found, check:
1. Package registered in `pkgs/default.nix`
2. Overlay applied in your configuration
3. System matches supported platform
### Linting Errors
```bash
# Fix statix issues manually or use auto-fix where available
statix fix .
# Review deadnix suggestions
deadnix -e .
```
## Getting Help
- Check existing packages and modules for patterns
- Read [Architecture](./ARCHITECTURE.md) for design decisions
- Review [Code Patterns](./reference/patterns.md) for conventions
- Open an issue for questions
## Anti-Patterns
| Don't | Do Instead |
|-------|------------|
| `lib.fakeHash` in commits | Get real hash: `nix build`, copy from error |
| Flat module files | Organize by category (`cli/`, `coding/`) |
| Hardcode ports | Use `m3ta.ports` module |
| Skip meta fields | Include all: description, homepage, license, platforms, mainProgram |
| `with pkgs;` in modules | Explicit `pkgs.package` or `with pkgs; [ ... ]` in lists only |
| Suppress type errors | Fix underlying type issues |
| Delete tests to "pass" | Fix failing tests |
## Code Review Checklist
- [ ] Follows naming conventions
- [ ] Properly formatted (`nix fmt`)
- [ ] Passes linting (`statix`, `deadnix`)
- [ ] Has complete `meta` fields (packages)
- [ ] Documentation updated if needed
- [ ] No dead code
- [ ] No obvious bugs or issues
- [ ] Appropriate for scope
## Release Process
This is a personal repository, but semantic versioning is followed for tags:
1. Update versions as needed
2. Update changelog
3. Tag release
4. Push tags
```bash
git tag -a v1.0.0 -m "Release v1.0.0"
git push origin v1.0.0
```
+316
View File
@@ -0,0 +1,316 @@
# Quick Start Guide
Get started with m3ta-nixpkgs in 5 minutes.
## Prerequisites
- Nix with flakes enabled (Nix 2.4+)
- Basic familiarity with NixOS and/or Home Manager
Enable flakes in `/etc/nixos/configuration.nix`:
```nix
nix.settings.experimental-features = ["nix-command" "flakes"];
```
## Adding to Your Flake
### NixOS Configuration
```nix
{
description = "My NixOS configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
m3ta-nixpkgs = {
url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
home-manager,
m3ta-nixpkgs,
...
}: {
nixosConfigurations = {
hostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./hardware-configuration.nix
# Import m3ta's NixOS modules
m3ta-nixpkgs.nixosModules.default
# Apply overlay to make packages available
({pkgs, ...}: {
nixpkgs.overlays = [m3ta-nixpkgs.overlays.default];
environment.systemPackages = with pkgs; [
code2prompt
zellij-ps
# Regular nixpkgs packages
vim
];
})
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.yourusername = {
imports = [m3ta-nixpkgs.homeManagerModules.default];
home.packages = with pkgs; [
launch-webapp
];
};
}
];
};
};
};
}
```
### Standalone Home Manager
```nix
{
description = "My Home Manager configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
m3ta-nixpkgs = {
url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
home-manager,
m3ta-nixpkgs,
} @ inputs: let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
overlays = [m3ta-nixpkgs.overlays.default];
};
in {
homeConfigurations.yourusername = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
extraSpecialArgs = {inherit inputs;};
modules = [
m3ta-nixpkgs.homeManagerModules.default
{
home.username = "yourusername";
home.homeDirectory = "/home/yourusername";
home.packages = with pkgs; [
code2prompt
zellij-ps
];
programs.home-manager.enable = true;
}
];
};
};
}
```
## Using Packages Without Configuration
You can build and run packages directly without adding to your configuration:
```bash
# Build a package
nix build git+https://code.m3ta.dev/m3tam3re/nixpkgs#code2prompt
# Run a package
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#zellij-ps
# List all available packages
nix flake show git+https://code.m3ta.dev/m3tam3re/nixpkgs
```
## Common Use Cases
### Use a Package System-Wide
```nix
# In configuration.nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
code2prompt # From m3ta-nixpkgs
git # From nixpkgs
];
}
```
### Use a Package for Your User Only
```nix
# In home.nix
{pkgs, ...}: {
home.packages = with pkgs; [
launch-webapp
zellij-ps
];
}
```
### Use a NixOS Module
```nix
{config, ...}: {
imports = [
# Or import the default which includes all modules
];
# Enable mem0 service
m3ta.mem0 = {
enable = true;
port = 8000;
llm = {
provider = "openai";
apiKeyFile = "/run/secrets/openai-api-key";
};
};
}
```
### Use Port Management
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
hostOverrides.laptop = {
nginx = 8080; # Override on laptop
};
currentHost = config.networking.hostName;
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
}
'';
};
}
```
## Available Packages
| Package | Description |
| ------------------ | ------------------------------------- |
| `code2prompt` | Convert code to prompts |
| `hyprpaper-random` | Random wallpaper setter for Hyprpaper |
| `launch-webapp` | Launch web applications |
| `mem0` | AI memory assistant with vector storage |
| `msty-studio` | Msty Studio application |
| `pomodoro-timer` | Pomodoro timer utility |
| `tuxedo-backlight` | Backlight control for Tuxedo laptops |
| `zellij-ps` | Project switcher for Zellij |
## Essential Commands
```bash
# Validate your configuration
nix flake check
# Format Nix files
nix fmt
# Apply NixOS configuration
sudo nixos-rebuild switch
# Apply Home Manager configuration
home-manager switch
# Enter development shell
nix develop .#python # Python shell
nix develop .#devops # DevOps shell
# List all outputs
nix flake show
```
## Development Workflow
```bash
# Clone repository
git clone https://code.m3ta.dev/m3tam3re/nixpkgs.git
cd nixpkgs
# Create a new package
nix flake init -t .#package
# Test package build
nix build .#your-package
# Run linting (in dev shell)
nix develop
statix check .
deadnix .
# Format before commit
nix fmt
```
## Troubleshooting
### Package Not Found
Make sure you applied the overlay:
```nix
nixpkgs.overlays = [m3ta-nixpkgs.overlays.default];
```
Or reference directly:
```nix
inputs.m3ta-nixpkgs.packages.${pkgs.system}.package-name
```
### Module Not Found
Make sure you imported the module:
```nix
imports = [
m3ta-nixpkgs.nixosModules.default
# or specific module:
m3ta-nixpkgs.nixosModules.mem0
];
```
### Hash Mismatch
If you're developing and get a hash error, rebuild to get the real hash:
```bash
nix build .#your-package
# Copy hash from error and update package
```
## Next Steps
- [Architecture](./ARCHITECTURE.md) - Understanding the repository structure
- [Adding Packages](./guides/adding-packages.md) - How to add new packages
- [Using Modules](./guides/using-modules.md) - Deep dive into modules
- [Port Management](./guides/port-management.md) - Managing service ports
+143
View File
@@ -0,0 +1,143 @@
# m3ta-nixpkgs Documentation
Complete documentation for m3ta's personal Nix flake repository.
## Overview
m3ta-nixpkgs is a collection of custom packages, overlays, NixOS modules, and Home Manager modules organized as a modern Nix flake. This repository follows a flakes-only approach (no channels) and provides reusable components for personal infrastructure.
## Getting Started
- **[Quick Start Guide](./QUICKSTART.md)** - Get up and running in 5 minutes
- **[Architecture](./ARCHITECTURE.md)** - Understanding the repository structure and design
- **[Contributing](./CONTRIBUTING.md)** - How to contribute to this repository
## Documentation Sections
### 📚 Guides
Step-by-step guides for common tasks:
- [Getting Started](./guides/getting-started.md) - Initial setup and basic usage
- [Adding Packages](./guides/adding-packages.md) - How to add new packages
- [Adding Modules](./guides/adding-modules.md) - How to add new NixOS or Home Manager modules
- [Port Management](./guides/port-management.md) - Managing service ports across hosts
- [Using Modules](./guides/using-modules.md) - Using NixOS and Home Manager modules
- [Development Workflow](./guides/development-workflow.md) - Development and testing workflow
### 📦 Packages
- [Packages Index](./packages/) - All packages with descriptions
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Templates](../templates.md) - Boilerplate templates
### ⚙️ Modules
Configuration modules for NixOS and Home Manager:
#### NixOS Modules
- [Overview](./modules/nixos/overview.md) - NixOS modules overview
- [mem0](./modules/nixos/mem0.md) - Mem0 REST API server module
- [ports](./modules/nixos/ports.md) - Port management module
#### Home Manager Modules
- [Overview](./modules/home-manager/overview.md) - Home Manager modules overview
- [CLI Tools](./modules/home-manager/cli/) - CLI-related modules
- [rofi-project-opener](./modules/home-manager/cli/rofi-project-opener.md) - Rofi-based project launcher
- [stt-ptt](./modules/home-manager/cli/stt-ptt.md) - Push to Talk Speech to Text
- [zellij-ps](./modules/home-manager/cli/zellij-ps.md) - Zellij project switcher
- [Coding](./modules/home-manager/coding/) - Development-related modules
- [editors](./modules/home-manager/coding/editors.md) - Editor configurations
### 📖 Reference
Technical references and APIs:
- [Functions](./reference/functions.md) - Library functions documentation
- [Patterns](./reference/patterns.md) - Code patterns and anti-patterns
- [Templates](../templates.md) - Boilerplate for packages and modules
## Repository Structure
```
m3ta-nixpkgs/
├── docs/ # This directory
│ ├── README.md
│ ├── QUICKSTART.md
│ ├── ARCHITECTURE.md
│ ├── CONTRIBUTING.md
│ ├── guides/
│ ├── packages/
│ ├── modules/
│ └── reference/
├── pkgs/ # Custom packages
├── modules/
│ ├── nixos/ # NixOS modules
│ └── home-manager/ # Home Manager modules
├── lib/ # Library functions
├── shells/ # Development shells
├── overlays/ # Package overlays
├── templates/ # Templates
└── examples/ # Usage examples
```
## Key Concepts
### Flakes-Only Approach
This repository uses modern Nix flakes exclusively. No channels or `nix-channel` commands are needed. All dependencies are declaratively specified in `flake.nix`.
### Namespace Convention
All modules use the `m3ta.*` namespace:
- `m3ta.ports.*` - Port management
- `m3ta.mem0.*` - Mem0 service configuration
- `m3ta.*.enable` - Enable/disable modules
### Port Management
Centralized port management across hosts using the `m3ta.ports` module:
```nix
m3ta.ports = {
enable = true;
definitions = { mem0 = 8000; };
hostOverrides.laptop = { mem0 = 8080; };
currentHost = "laptop";
};
```
## Supported Systems
- `x86_64-linux` - Primary
- `aarch64-linux` - ARM Linux
- `x86_64-darwin` - macOS (Intel)
- `aarch64-darwin` - macOS (Apple Silicon)
## Quick Commands
```bash
# Validate flake
nix flake check
# Format code
nix fmt
# Build package
nix build .#<package-name>
# List outputs
nix flake show
# Enter dev shell
nix develop
```
## License
Individual packages may have their own licenses. Check each package's `meta.license` attribute.
## Maintainer
[@m3tam3re](https://m3ta.dev)
+261
View File
@@ -0,0 +1,261 @@
# Adding Modules Guide
How to add new NixOS and Home Manager modules to m3ta-nixpkgs.
## Overview
Modules extend your system or user configuration with reusable, declarative options. m3ta-nixpkgs uses the standard NixOS module system with a `m3ta.*` namespace.
## Quick Start
Use a template for quick setup:
```bash
# NixOS module
nix flake init -t .#nixos-module my-module
# Home Manager module
nix flake init -t .#home-manager-module my-module
```
This copies the template into `templates/` — move it to the appropriate location and customize.
## Adding a NixOS Module
### 1. Create the Module File
Create `modules/nixos/<my-module>.nix`:
```nix
{config, lib, pkgs, ...}:
with lib; let
cfg = config.m3ta.myModule;
in {
options.m3ta.myModule = {
enable = mkEnableOption "my module description";
# Add custom options here
someOption = mkOption {
type = types.str;
default = "default-value";
description = "Description of this option";
};
};
config = mkIf cfg.enable {
# System configuration goes here
environment.systemPackages = [pkgs.some-package];
# Or systemd services
systemd.services.my-service = {
enable = true;
description = "My service";
wantedBy = ["multi-user.target"];
serviceConfig = {
ExecStart = "${pkgs.some-package}/bin/some-daemon";
};
};
};
}
```
### 2. Register in the Aggregator
Add to `modules/nixos/default.nix`:
```nix
{
imports = [
./ports.nix
./mem0.nix
./<my-module>.nix # ← add your module
];
}
```
### 3. Export from flake.nix
Add to the `nixosModules` output in `flake.nix` (optional, for direct import):
```nix
nixosModules = {
default = ./modules/nixos;
ports = ./modules/nixos/ports.nix;
mem0 = ./modules/nixos/mem0.nix;
my-module = ./modules/nixos/<my-module>.nix; # ← add this
};
```
## Adding a Home Manager Module
Home Manager modules are organized by category under `modules/home-manager/`.
### Categories
| Category | Purpose | Location |
|----------|---------|----------|
| `cli/` | Command-line tools and utilities | `modules/home-manager/cli/` |
| `coding/` | Development tools, editors, agents | `modules/home-manager/coding/` |
| Root | Cross-cutting concerns (e.g., ports) | `modules/home-manager/` |
### 1. Choose a Category
- **CLI tools** (zsh plugins, tmux config, etc.) → `cli/`
- **Development tools** (editor config, linters, etc.) → `coding/`
- **System-wide settings** (ports, environment) → root level
### 2. Create the Module File
Create `modules/home-manager/<category>/<my-module>.nix`:
```nix
{config, lib, pkgs, ...}:
with lib; let
cfg = config.m3ta.myModule;
in {
options.m3ta.myModule = {
enable = mkEnableOption "my user module description";
someOption = mkOption {
type = types.str;
default = "value";
description = "An option for this module";
};
};
config = mkIf cfg.enable {
home.packages = [pkgs.some-package];
# Or Home Manager-specific options
programs.zsh.enable = true;
};
}
```
### 3. Register in the Category Aggregator
For `cli/` modules, add to `modules/home-manager/cli/default.nix`:
```nix
{
imports = [
./rofi-project-opener.nix
./stt-ptt.nix
./zellij-ps.nix
./<my-module>.nix # ← add your module
];
}
```
For `coding/` modules, add to `modules/home-manager/coding/default.nix`:
```nix
{
imports = [
./editors.nix
./opencode.nix
./agents
./<my-module>.nix # ← add your module
];
}
```
### 4. Export from flake.nix
Add to `homeManagerModules` in `flake.nix`:
```nix
homeManagerModules = {
default = import ./modules/home-manager;
my-module = import ./modules/home-manager/<category>/<my-module>.nix; # ← add this
};
```
## Module Patterns
### Standard Enable Option
Always start with `mkEnableOption`:
```nix
options.m3ta.myModule = {
enable = mkEnableOption "my module";
};
```
### Conditional Configuration
Use `mkIf` for conditional config:
```nix
config = mkIf cfg.enable {
# Only applied when enabled
};
```
### Multiple Conditions
Use `mkMerge` when combining multiple conditional blocks:
```nix
config = mkMerge [
(mkIf cfg.feature1.enable { ... })
(mkIf cfg.feature2.enable { ... })
];
```
### Nested Namespaces
For logically grouped options, use nested namespaces:
```nix
options.m3ta.coding = {
myTool = {
enable = mkEnableOption "my coding tool";
# ...
};
};
```
Usage: `m3ta.coding.myTool.enable = true;`
### Shared Library Functions
For shared utilities (port helpers, etc.), import from `lib/`:
```nix
let
portsLib = import ../../lib/ports.nix {inherit lib;};
portHelpers = portsLib.mkPortHelpers { /* ... */ };
in {
# use portHelpers
}
```
## Documentation
Add documentation for your module:
1. Create `docs/modules/nixos/<my-module>.md` (NixOS) or `docs/modules/home-manager/<category>/<my-module>.md` (HM)
2. Follow the existing format in `docs/modules/`
3. Add it to the appropriate overview page's "Available Modules" list
4. Link it from `docs/guides/using-modules.md`
## Testing
```bash
# Validate the module loads correctly
nix flake check
# Test with a minimal configuration (NixOS)
nixos-rebuild dry-build -I nixpkgs=. --option experimental-features flakes
# Format before commit
nix fmt
```
## Related
- [Using Modules](./using-modules.md) - How to use existing modules
- [Port Management](./port-management.md) - Centralized port management
- [Development Workflow](./development-workflow.md) - Local development
- [Adding Packages](./adding-packages.md) - Adding packages (not modules)
- [Architecture](../ARCHITECTURE.md) - Repository structure
+504
View File
@@ -0,0 +1,504 @@
# Adding Packages Guide
How to add new packages to m3ta-nixpkgs.
## Overview
Packages in m3ta-nixpkgs are organized using a `callPackage` registry pattern. Each package lives in its own directory and is registered centrally.
## Quick Start
### Using Templates
Use the package template for quick setup:
```bash
nix flake init -t .#package my-new-package
```
This creates a template structure in `templates/package/` that you can copy.
### Automatic Updates
**Important**: This repository uses automated package updates via Gitea Actions and `nix-update`. When adding a new package:
- Use any stable, working version for the initial package
- You don't need to use the absolute latest version
- The automation will keep the package updated automatically on a weekly basis
- Review and merge automated update PRs as they come in
See the main README.md for more details on the automated update workflow.
### Manual Setup
1. Create directory: `pkgs/your-package/`
2. Write `default.nix` with package definition
3. Register in `pkgs/default.nix`
## Package Structure
```
pkgs/your-package/
├── default.nix # Package definition (required)
├── source.py # Optional: additional source files
├── wrapper.sh # Optional: wrapper scripts
└── README.md # Optional: package documentation
```
## Common Patterns
### Rust Package
```nix
{
lib,
rustPlatform,
fetchFromGitHub,
}:
rustPlatform.buildRustPackage rec {
pname = "my-rust-app";
version = "1.0.0";
src = fetchFromGitHub {
owner = "author";
repo = "my-rust-app";
rev = "v${version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
cargoLock.lockFile = src + "/Cargo.lock";
buildInputs = [openssl];
nativeBuildInputs = [pkg-config];
meta = with lib; {
description = "My Rust application";
homepage = "https://github.com/author/my-rust-app";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "my-rust-app";
};
}
```
### Python Package
```nix
{
lib,
python3,
fetchFromGitHub,
}:
python3.pkgs.buildPythonPackage rec {
pname = "my-python-app";
version = "1.0.0";
pyproject = true;
src = fetchFromGitHub {
owner = "author";
repo = "my-python-app";
rev = "v${version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
build-system = with python3.pkgs; [setuptools];
dependencies = with python3.pkgs; [
requests
click
];
optional-dependencies = with python3.pkgs; {
extras = [pyyaml];
};
doCheck = true;
pythonImportsCheck = ["myapp"];
meta = with lib; {
description = "My Python application";
homepage = "https://github.com/author/my-python-app";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "my-app";
};
}
```
### Shell Script Package
```nix
{
lib,
writeShellScriptBin,
}:
writeShellScriptBin "my-script" ''
#!/usr/bin/env bash
set -euo pipefail
echo "Hello from my script!"
# Your script logic here
''
# If you need to add dependencies
{
lib,
writeShellApplication,
bash,
curl,
}:
writeShellApplication {
name = "my-script";
runtimeInputs = [bash curl];
text = ''
#!/usr/bin/env bash
set -euo pipefail
curl -s https://example.com
'';
}
```
### AppImage Package
```nix
{
lib,
appimageTools,
fetchurl,
}:
appimageTools.wrapType2 rec {
name = "my-app";
version = "1.0.0";
src = fetchurl {
url = "https://github.com/author/my-app/releases/download/v${version}/My-App-${version}.AppImage";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
meta = with lib; {
description = "My AppImage application";
homepage = "https://github.com/author/my-app";
license = licenses.unfree;
platforms = platforms.linux;
mainProgram = name;
};
}
```
### Custom Source with Patch
```nix
{
lib,
stdenv,
fetchFromGitHub,
fetchpatch,
buildGoModule,
}:
buildGoModule rec {
pname = "my-go-app";
version = "1.0.0";
src = fetchFromGitHub {
owner = "author";
repo = "my-go-app";
rev = "v${version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
patches = [
# Add local patch
./fix-build.patch
# Add patch from URL
(fetchpatch {
url = "https://github.com/author/my-app/pull/123.patch";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
})
];
vendorHash = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
meta = with lib; {
description = "My Go application";
homepage = "https://github.com/author/my-go-app";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "my-app";
};
}
```
### Package with Custom Installation
```nix
{
lib,
stdenv,
fetchFromGitHub,
makeWrapper,
}:
stdenv.mkDerivation rec {
pname = "my-app";
version = "1.0.0";
src = fetchFromGitHub {
owner = "author";
repo = "my-app";
rev = "v${version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
nativeBuildInputs = [makeWrapper];
buildPhase = ''
make build
'';
installPhase = ''
install -Dm755 my-app $out/bin/my-app
# Wrap with runtime dependencies
wrapProgram $out/bin/my-app \
--prefix PATH : ${lib.makeBinPath [some-dep]}
'';
meta = with lib; {
description = "My custom application";
homepage = "https://github.com/author/my-app";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "my-app";
};
}
```
## Registration
### Register in `pkgs/default.nix`
Add your package to the registry:
```nix
{
inherit (pkgs) callPackage;
} rec {
# Existing packages
code2prompt = callPackage ./code2prompt {};
zellij-ps = callPackage ./zellij-ps {};
# Your new package
my-new-package = callPackage ./my-new-package {};
}
```
### With Custom Arguments
If your package needs custom arguments:
```nix
# pkgs/default.nix
{
inherit (pkgs) callPackage;
} rec {
my-new-package = callPackage ./my-new-package {
customArg = "value";
};
}
# pkgs/my-new-package/default.nix
{
lib,
stdenv,
fetchurl,
customArg, # This will be passed from the registry
}:
stdenv.mkDerivation {
# ...
}
```
## Getting Hashes
### Using `lib.fakeHash`
During development, use `lib.fakeHash` to get the real hash:
```nix
src = fetchFromGitHub {
owner = "author";
repo = "my-app";
rev = "v${version}";
hash = lib.fakeHash; # Temporary placeholder
};
```
Build the package:
```bash
nix build .#my-new-package
```
Copy the actual hash from the error message and update the package:
```nix
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Real hash
```
**Important**: Never commit `lib.fakeHash` to the repository.
## Testing
### Build Package
```bash
nix build .#my-new-package
```
### Test Execution
```bash
nix run .#my-new-package -- --help
```
### Run in Shell
```bash
nix shell .#my-new-package
my-new-app --version
```
### Linting
```bash
nix develop
statix check pkgs/my-new-package/
```
## Best Practices
### Meta Fields
Always include complete `meta` information:
```nix
meta = with lib; {
description = "Short one-line description";
longDescription = ''
Longer description explaining what the package does,
its features, and use cases.
'';
homepage = "https://github.com/author/repo";
changelog = "https://github.com/author/repo/releases/tag/v${version}";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "program-name";
};
```
### Dependencies
Explicitly declare all dependencies:
```nix
{
lib,
stdenv,
fetchFromGitHub,
# Runtime dependencies
openssl,
curl,
# Native build dependencies
pkg-config,
cmake,
}:
```
### Versioning
Use `rec` to reference `version` in multiple places:
```nix
rec {
pname = "my-app";
version = "1.0.0";
src = fetchFromGitHub {
rev = "v${version}";
# ...
};
}
```
### Platform Restrictions
If package is platform-specific:
```nix
meta = with lib; {
# Linux only
platforms = platforms.linux;
# Or specific platforms
platforms = ["x86_64-linux" "aarch64-linux"];
# Or exclude platforms
broken = stdenv.isDarwin;
};
```
## Troubleshooting
### Hash Mismatch
Error: `got: sha256-AAAAAAAA... expected: sha256-BBBBBB...`
Solution: Copy `got` hash and update package definition.
### Dependency Not Found
Error: `error: undefined variable 'somedep'`
Solution: Add dependency to function arguments and build inputs:
```nix
{
lib,
somedep, # Add here
}:
stdenv.mkDerivation {
buildInputs = [somedep]; # Add here
}
```
### Import Check Failure
Error: `error: Python module 'mymodule' not found`
Solution: Disable or fix imports check:
```nix
pythonImportsCheck = ["mymodule"]; # Check this is correct
# Or if importing creates side effects:
pythonImportsCheck = [];
```
## Examples
See existing packages in the repository:
- `pkgs/code2prompt/` - Rust package
- `pkgs/mem0/` - Python package
- `pkgs/hyprpaper-random/` - Shell script
- `pkgs/msty-studio/` - AppImage
- `pkgs/zellij-ps/` - Fetch from Gitea
## Next Steps
- [Architecture](../ARCHITECTURE.md) - Understanding package organization
- [Using Modules](./using-modules.md) - If you need to create modules
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines
+527
View File
@@ -0,0 +1,527 @@
# Development Workflow Guide
Development, testing, and contribution workflow for m3ta-nixpkgs.
## Initial Setup
### Clone Repository
```bash
git clone https://code.m3ta.dev/m3tam3re/nixpkgs.git
cd nixpkgs
```
### Enter Development Shell
```bash
# Default shell (includes linting tools)
nix develop
# Python shell
nix develop .#python
# DevOps shell
nix develop .#devops
```
### Development Shell Tools
The default dev shell includes:
- `statix` - Nix linter
- `deadnix` - Find dead code
- `alejandra` - Code formatter
## Workflow
### 1. Create Feature Branch
```bash
# Checkout main and pull latest
git checkout main
git pull
# Create feature branch
git checkout -b feature/my-new-package
```
### 2. Make Changes
```bash
# Create new package
mkdir -p pkgs/my-package
vim pkgs/my-package/default.nix
# Or modify existing package
vim pkgs/existing-package/default.nix
# Or add module
vim modules/nixos/my-module.nix
```
### 3. Format Code
```bash
# Format all files
nix fmt
# Format specific file
alejandra path/to/file.nix
```
**Always format before committing.**
### 4. Test Changes
#### Build Package
```bash
# Build specific package
nix build .#my-package
# Build all packages
nix build .#packages.x86_64-linux
```
#### Run Package
```bash
# Test if package runs
nix run .#my-package -- --help
# Or enter shell with package
nix shell .#my-package
my-package --version
```
#### Validate Flake
```bash
# Validate all outputs
nix flake check
# Show all outputs
nix flake show
```
#### Test Module
```bash
# Test NixOS configuration
sudo nixos-rebuild test --flake .#hostname
# Test Home Manager configuration
home-manager switch --flake .#username@hostname
```
### 5. Lint Code
```bash
# Enter dev shell for linting tools
nix develop
# Run statix
statix check .
# Run deadnix
deadnix .
# Fix auto-fixable issues
statix fix .
```
### 6. Commit Changes
```bash
# Stage changes
git add .
# Commit with conventional format
git commit -m "feat: add my-package for doing X"
# Commit types: feat, fix, docs, style, refactor, chore, test
```
### 7. Push and Create PR
```bash
# Push branch
git push origin feature/my-new-package
# Create PR via web interface or CLI
gh pr create --title "feat: add my-package" --body "Description of changes"
```
## Testing Strategies
### Local Testing
#### Test Package Build
```bash
# Build for current system
nix build .#my-package
# Build for specific system
nix build .#my-package --system aarch64-linux
# Build for macOS
nix build .#my-package --system x86_64-darwin
```
#### Test Package Functionality
```bash
# Enter shell with package
nix shell .#my-package
# Run the program
my-package --help
my-package --version
# Test with sample data
echo "test" | my-package
```
#### Test Configuration
```bash
# Test NixOS configuration
sudo nixos-rebuild test --flake .#hostname
# Test Home Manager configuration
home-manager switch --flake .#username@hostname
# Check configuration syntax
nix eval .#nixosConfigurations.hostname.config --apply builtins.attrNames
```
### Integration Testing
#### Test with Real Services
```bash
# If package is a service
# 1. Add to configuration
# 2. Apply configuration
sudo nixos-rebuild switch
# 3. Test service
systemctl status my-service
journalctl -u my-service -f
# 4. Test functionality
curl http://localhost:8080
```
#### Test with Dependencies
```bash
# Build dependency chain
nix build .#my-package \
--rebuild \
--keep-going
# Check if dependencies are satisfied
nix path-info .#my-package --references
```
## Continuous Integration
### Pre-Commit Hook
Create `.git/hooks/pre-commit`:
```bash
#!/usr/bin/env bash
set -euo pipefail
# Format code
nix fmt
# Lint
statix check .
deadnix .
# Validate
nix flake check
# Test build
nix build .#your-package
```
Make executable:
```bash
chmod +x .git/hooks/pre-commit
```
### Pre-Push Hook
Create `.git/hooks/pre-push`:
```bash
#!/usr/bin/env bash
set -euo pipefail
# Validate flake
nix flake check
# Run tests if they exist
# make test
```
## Debugging
### Build Failures
#### Hash Mismatch
Error: `got: sha256-AAAAAAAA... expected: sha256-BBBBBB...`
Solution: Copy the `got` hash and update package:
```nix
src = fetchFromGitHub {
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Use actual hash
};
```
#### Dependency Not Found
Error: `error: undefined variable 'somelib'`
Solution: Check function arguments:
```nix
{
lib,
stdenv,
fetchFromGitHub,
somelib, # Add this if missing
}:
```
#### Build Failed
Error: `builder for '/nix/store/...' failed`
Solution:
```bash
# Build with verbose output
nix build .#my-package -v --show-trace
# Check build logs
nix log .#my-package
# Enter build environment for debugging
nix shell -f .#my-package .bashInteractive
```
### Runtime Failures
#### Package Not Executable
Error: `error: operation not permitted`
Solution: Check `mainProgram` in meta:
```nix
meta = with lib; {
mainProgram = "my-app"; # Must match executable name
};
```
#### Library Not Found
Error: `error while loading shared libraries: libfoo.so`
Solution: Add to build inputs:
```nix
buildInputs = [someLib];
```
### Configuration Failures
#### Option Not Found
Error: `error: The option 'm3ta.mymodule' does not exist`
Solution: Import the module:
```nix
imports = [
m3ta-nixpkgs.nixosModules.default
];
```
## Common Tasks
### Update Package Version
```bash
# 1. Update version in package definition
vim pkgs/my-package/default.nix
# 2. Build to get new hash
nix build .#my-package
# 3. Update hash from error message
# 4. Test new version
nix run .#my-package -- --version
# 5. Commit
git commit -m "chore: update my-package to v2.0.0"
```
### Update Dependencies
```bash
# 1. Update fetcher version/rev
vim pkgs/my-package/default.nix
# 2. Update dependencies if needed
vim pkgs/my-package/default.nix
# 3. Build and test
nix build .#my-package
nix run .#my-package -- --help
# 4. Commit
git commit -m "fix: update dependencies for my-package"
```
### Add Tests
```bash
# 1. Add test to package
vim pkgs/my-package/default.nix
# 2. Run tests
nix build .#my-package
# 3. Verify tests pass
# 4. Commit
git commit -m "test: add tests for my-package"
```
### Fix Linting Issues
```bash
# 1. Run linter
nix develop
statix check .
# 2. Fix issues manually or auto-fix
statix fix .
# 3. Check again
statix check .
# 4. Commit
git commit -m "style: fix linting issues"
```
## Performance Optimization
### Use Caching
```bash
# Use binary cache (if available)
nix build .#my-package --substituters https://cache.nixos.org https://your-cache.example.com
# Use local cache
nix build .#my-package --max-jobs 4
```
### Parallel Builds
```bash
# Build multiple packages in parallel
nix build .#package1 .#package2 .#package3
```
### Incremental Builds
```bash
# Only rebuild changed packages
nix build .#my-package --check
# Don't rebuild dependencies
nix build .#my-package --no-link
```
## Release Process
### Version Bump
```bash
# 1. Update versions as needed
vim pkgs/*/default.nix
# 2. Update CHANGELOG.md
vim CHANGELOG.md
# 3. Test all packages
nix flake check
# 4. Commit
git commit -m "chore: prepare release v1.0.0"
```
### Tag Release
```bash
# Create tag
git tag -a v1.0.0 -m "Release v1.0.0"
# Push tag
git push origin v1.0.0
# Push with tags
git push --follow-tags
```
### Update Flakes
Update flake lock after release:
```bash
# Update lock file
nix flake update
# Commit
git commit -m "chore: update flake lock"
```
## Checklist
### Before Committing
- [ ] Code formatted with `nix fmt`
- [ ] Passes `statix check .`
- [ ] Passes `deadnix .`
- [ ] Passes `nix flake check`
- [ ] Package builds successfully
- [ ] Package runs as expected
- [ ] Documentation updated (if needed)
- [ ] Commit message follows convention
### Before Merging PR
- [ ] All tests pass
- [ ] Code review approved
- [ ] No merge conflicts
- [ ] Documentation complete
- [ ] Breaking changes documented
## Resources
- [Contributing Guide](../CONTRIBUTING.md) - Code style and guidelines
- [Architecture](../ARCHITECTURE.md) - Understanding repository structure
- [Adding Packages](./adding-packages.md) - Package creation guide
- [Quick Start](../QUICKSTART.md) - Getting started guide
+402
View File
@@ -0,0 +1,402 @@
# Getting Started Guide
Initial setup and basic usage of m3ta-nixpkgs.
## Installation
### Prerequisites
Make sure you have Nix installed with flakes enabled:
```bash
# Check Nix version (need 2.4+)
nix --version
# Enable flakes (in /etc/nixos/configuration.nix)
nix.settings.experimental-features = ["nix-command" "flakes"]
# Rebuild NixOS
sudo nixos-rebuild switch
```
### Adding to Your Flake
#### Option 1: NixOS Configuration
Add to your `flake.nix`:
```nix
{
description = "My NixOS configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
m3ta-nixpkgs = {
url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
home-manager,
m3ta-nixpkgs,
...
}: {
nixosConfigurations = {
myhost = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./hardware-configuration.nix
# Import m3ta-nixpkgs modules
m3ta-nixpkgs.nixosModules.default
# Apply overlay
({pkgs, ...}: {
nixpkgs.overlays = [m3ta-nixpkgs.overlays.default];
# Packages from m3ta-nixpkgs are now available
environment.systemPackages = with pkgs; [
code2prompt
zellij-ps
];
})
# Home Manager integration
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.myusername = {
imports = [m3ta-nixpkgs.homeManagerModules.default];
home.packages = with pkgs; [
launch-webapp
];
};
}
];
};
};
};
}
```
#### Option 2: Standalone Home Manager
```nix
{
description = "My Home Manager configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
m3ta-nixpkgs = {
url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
home-manager,
m3ta-nixpkgs,
}: let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
overlays = [m3ta-nixpkgs.overlays.default];
};
in {
homeConfigurations.myusername = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
modules = [
m3ta-nixpkgs.homeManagerModules.default
{
home.username = "myusername";
home.homeDirectory = "/home/myusername";
home.packages = with pkgs; [
code2prompt
zellij-ps
];
programs.home-manager.enable = true;
}
];
};
};
}
```
## Quick Usage
### Using Packages Directly
Without adding to your configuration:
```bash
# Build a package
nix build git+https://code.m3ta.dev/m3tam3re/nixpkgs#code2prompt
# Run a package
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#zellij-ps
# List all available packages
nix flake show git+https://code.m3ta.dev/m3tam3re/nixpkgs
```
### Using Packages in Configuration
After applying overlay:
```nix
# System-wide (NixOS)
environment.systemPackages = with pkgs; [
code2prompt
zellij-ps
];
# User-only (Home Manager)
home.packages = with pkgs; [
launch-webapp
];
```
### Using Modules
```nix
# Import all modules
imports = [
m3ta-nixpkgs.nixosModules.default
];
# Or import specific module
imports = [
m3ta-nixpkgs.nixosModules.mem0
];
# Configure module
m3ta.mem0 = {
enable = true;
port = 8000;
};
```
## Common Tasks
### Install a Package System-Wide
```nix
# /etc/nixos/configuration.nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
code2prompt
hyprpaper-random
];
}
# Apply
sudo nixos-rebuild switch
```
### Install a Package for Your User
```nix
# home.nix
{pkgs, ...}: {
home.packages = with pkgs; [
launch-webapp
zellij-ps
];
}
# Apply
home-manager switch
```
### Enable a NixOS Module
```nix
# /etc/nixos/configuration.nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
m3ta.mem0 = {
enable = true;
port = 8000;
};
# Apply
# sudo nixos-rebuild switch
}
```
### Enable a Home Manager Module
```nix
# home.nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
cli.zellij-ps = {
enable = true;
};
# Apply
# home-manager switch
}
```
### Use Port Management
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
hostOverrides.laptop = {
nginx = 8080;
};
currentHost = config.networking.hostName;
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
}
```
## Available Packages
| Package | Description |
| ------------------ | ------------------------------------- |
| `code2prompt` | Convert code to prompts |
| `hyprpaper-random` | Random wallpaper setter for Hyprpaper |
| `launch-webapp` | Launch web applications |
| `mem0` | AI memory assistant with vector storage |
| `msty-studio` | Msty Studio application |
| `pomodoro-timer` | Pomodoro timer utility |
| `tuxedo-backlight` | Backlight control for Tuxedo laptops |
| `zellij-ps` | Project switcher for Zellij |
## Available Modules
### NixOS Modules
- `ports` - Port management across hosts
- `mem0` - Mem0 REST API server
### Home Manager Modules
- `ports` - Port management (with `generateEnvVars`)
- `cli.zellij-ps` - Zellij project switcher
- `coding.editors` - Editor configurations
## Development
### Development Shells
```bash
# Default dev shell
nix develop
# Python dev shell
nix develop .#python
# DevOps dev shell
nix develop .#devops
```
### Building and Testing
```bash
# Build package
nix build .#code2prompt
# Validate flake
nix flake check
# List outputs
nix flake show
# Format code
nix fmt
```
### Linting (in dev shell)
```bash
nix develop
# Run linter
statix check .
# Find dead code
deadnix .
```
## Troubleshooting
### Package Not Found
**Error**: `error: undefined variable 'code2prompt'`
**Solution**: Make sure you applied the overlay:
```nix
nixpkgs.overlays = [m3ta-nixpkgs.overlays.default];
```
### Module Not Found
**Error**: `error: The option 'm3ta.mem0' does not exist`
**Solution**: Make sure you imported the module:
```nix
imports = [
m3ta-nixpkgs.nixosModules.default
# or
m3ta-nixpkgs.nixosModules.mem0
];
```
### Hash Mismatch
**Error**: `got: sha256-AAAAAAAA... expected: sha256-BBBBBB...`
**Solution**: Copy the `got` hash from the error and update the package definition.
### Building for Different System
```bash
# Build for aarch64-linux
nix build .#code2prompt --system aarch64-linux
# Build for macOS
nix build .#code2prompt --system x86_64-darwin
```
## Next Steps
- [Adding Packages](./adding-packages.md) - How to add new packages
- [Using Modules](./using-modules.md) - Deep dive into modules
- [Port Management](./port-management.md) - Managing service ports
- [Architecture](../ARCHITECTURE.md) - Understanding the repository structure
+525
View File
@@ -0,0 +1,525 @@
# Port Management Guide
Managing service ports across multiple hosts with the `m3ta.ports` module.
## Overview
The port management module provides a centralized way to define service ports that can have host-specific overrides. This prevents port conflicts and makes it easy to manage services across multiple machines.
## Basic Usage
### Enable Port Management
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
# Define default ports
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
homepage = 8080;
};
# Define host-specific overrides
hostOverrides = {
laptop = {
nginx = 8080; # Override on laptop
homepage = 3001; # Override on laptop
};
server = {
homepage = 3002; # Override on server
};
};
# Set current host (determines which overrides to use)
currentHost = config.networking.hostName;
};
}
```
### Using Ports
```nix
{config, ...}: {
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
}
```
## Module Options
### `m3ta.ports.enable`
Enable port management module.
- Type: `boolean`
- Default: `false`
### `m3ta.ports.definitions`
Default port definitions.
- Type: `attrsOf int`
- Default: `{}`
```nix
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
};
```
### `m3ta.ports.hostOverrides`
Host-specific port overrides.
- Type: `attrsOf (attrsOf int)`
- Default: `{}`
```nix
hostOverrides = {
laptop = {
nginx = 8080;
grafana = 3001;
};
server = {
grafana = 3002;
};
};
```
### `m3ta.ports.currentHost`
Current hostname. Determines which overrides to apply.
- Type: `string`
- Example: `config.networking.hostName`
```nix
currentHost = "laptop"; # Use laptop overrides
```
### `m3ta.ports.generateEnvVars` (Home Manager only)
Generate environment variables from ports.
- Type: `boolean`
- Default: `false` (Home Manager)
- NixOS: Not available
When enabled, generates environment variables like:
- `PORT_NGINX=8080`
- `PORT_GRAFANA=3000`
## Functions
### `config.m3ta.ports.get "service"`
Get port for a service with host-specific override.
```nix
services.nginx = {
port = config.m3ta.ports.get "nginx";
};
```
If current host is `laptop` and `hostOverrides.laptop.nginx = 8080`, returns `8080`.
If no override, returns default `80`.
### `config.m3ta.ports.getHostPorts "hostname"`
Get all ports for a specific host.
```nix
# Get all ports for laptop
laptopPorts = config.m3ta.ports.getHostPorts "laptop";
# Returns: { nginx = 8080; grafana = 3000; ... }
```
### `config.m3ta.ports.listServices`
List all defined service names.
```nix
allServices = config.m3ta.ports.listServices;
# Returns: ["nginx" "grafana" "prometheus" "homepage"]
```
## Examples
### NixOS Configuration
```nix
{config, ...}: {
# Define ports
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
loki = 3100;
promtail = 9080;
};
hostOverrides.laptop = {
nginx = 8080;
grafana = 3001;
};
currentHost = config.networking.hostName;
};
# Use ports
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
services.prometheus = {
enable = true;
port = config.m3ta.ports.get "prometheus";
};
services.loki = {
enable = true;
configuration.http_listen_port = config.m3ta.ports.get "loki";
};
}
```
### Home Manager Configuration
```nix
{config, ...}: {
# Define ports
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
nextjs = 3001;
vite = 5173;
};
hostOverrides.desktop = {
vite = 5174;
};
currentHost = "desktop";
generateEnvVars = true; # Generate env vars
};
# Ports are now available as env vars
# PORT_DEV_SERVER=3000
# PORT_NEXTJS=3001
# PORT_VITE=5174
home.sessionVariables = {
DEV_PORT = toString (config.m3ta.ports.get "dev-server");
};
}
```
### With Custom Modules
Using ports with custom modules (e.g., `m3ta.mem0`):
```nix
{config, ...}: {
# Define ports
m3ta.ports = {
enable = true;
definitions = {
mem0 = 8000;
qdrant = 6333;
};
hostOverrides.laptop = {
mem0 = 8080;
};
currentHost = config.networking.hostName;
};
# Use with mem0 module
m3ta.mem0 = {
enable = true;
port = config.m3ta.ports.get "mem0"; # 8000 or 8080 on laptop
};
# Use with qdrant service
services.qdrant = {
enable = true;
port = config.m3ta.ports.get "qdrant";
};
}
```
### Port File Generation
Generate a JSON file with all ports:
```nix
{config, pkgs, ...}: {
m3ta.ports = {
enable = true;
definitions = {
service1 = 80;
service2 = 443;
};
currentHost = config.networking.hostName;
};
# Generate port file
environment.etc."m3ta/ports.json".text = builtins.toJSON (
config.m3ta.ports.getHostPorts config.networking.hostName
);
}
```
## Advanced Usage
### Conditional Configuration
```nix
{config, ...}: {
services.nginx = {
enable = true;
# Only open firewall if binding to non-localhost
httpConfig = let
port = config.m3ta.ports.get "nginx";
in ''
server {
listen ${toString port};
}
'';
};
networking.firewall.allowedTCPPorts =
if config.m3ta.ports.get "nginx" == 80
then [80]
else [];
}
```
### Port Ranges
```nix
definitions = {
service-start = 8000;
service-end = 8999;
};
# Use in config
services.my-app = {
portRange = [
config.m3ta.ports.get "service-start"
config.m3ta.ports.get "service-end"
];
};
```
### Dynamic Port Allocation
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
# Reserve port ranges
app-range-start = 9000;
app-range-end = 9999;
};
currentHost = config.networking.hostName;
};
# Calculate next available port
services.my-app = {
port = config.m3ta.ports.get "app-range-start" + 0;
};
services.my-other-app = {
port = config.m3ta.ports.get "app-range-start" + 1;
};
}
```
## Best Practices
### Use Descriptive Service Names
```nix
# Good
definitions = {
nginx = 80;
grafana = 3000;
prometheus-ui = 9090;
prometheus-push = 9091;
};
# Avoid
definitions = {
p1 = 80;
p2 = 3000;
p3 = 9090;
};
```
### Group Related Services
```nix
definitions = {
# Monitoring stack
grafana = 3000;
prometheus = 9090;
loki = 3100;
promtail = 9080;
# Web services
nginx = 80;
homepage = 8080;
# Databases
postgres = 5432;
redis = 6379;
qdrant = 6333;
};
```
### Document Overrides
```nix
hostOverrides = {
# Laptop: Running multiple dev servers, use higher ports
laptop = {
nginx = 8080;
dev-server = 3000;
};
# Server: Production, use standard ports
server = {
nginx = 80;
dev-server = null; # Disable on server
};
};
```
### Handle Missing Ports
```nix
services.some-service = {
enable = true;
port = config.m3ta.ports.get "some-service" or 8080;
};
```
## Troubleshooting
### Service Not Found
Error: `Service "foo" not defined`
Solution: Add service to `definitions`:
```nix
definitions = {
foo = 8080;
};
```
### Current Host Not Set
Error: `currentHost not set`
Solution: Set `currentHost`:
```nix
currentHost = config.networking.hostName;
```
### Port Conflict
Issue: Two services trying to use same port.
Solution: Define both in port management:
```nix
definitions = {
service1 = 8080;
service2 = 8081; # Different port
};
```
## Migration from Hardcoded Ports
### Before
```nix
services.nginx = {
enable = true;
httpConfig = ''
server {
listen 80;
}
'';
};
services.grafana = {
enable = true;
settings.server.http_port = 3000;
};
```
### After
```nix
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
currentHost = config.networking.hostName;
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
}
'';
};
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
```
## Next Steps
- [Architecture](../ARCHITECTURE.md) - Understanding the library functions
- [Using Modules](./using-modules.md) - Using modules with port management
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines
+668
View File
@@ -0,0 +1,668 @@
# Using Modules Guide
How to use NixOS and Home Manager modules from m3ta-nixpkgs.
## Overview
Modules in m3ta-nixpkgs provide reusable configuration for NixOS (system-level) and Home Manager (user-level) settings. All modules use the `m3ta.*` namespace.
## Module Organization
### NixOS Modules
Located in `modules/nixos/`:
```
modules/nixos/
├── default.nix # Aggregates all NixOS modules
├── ports.nix # Port management
└── mem0.nix # Mem0 REST API server
```
### Home Manager Modules
Located in `modules/home-manager/` with categories:
```
modules/home-manager/
├── default.nix # Aggregates all HM modules
├── ports.nix # Port management
├── cli/ # CLI tools
│ ├── default.nix # Aggregates CLI modules
│ └── zellij-ps.nix
└── coding/ # Development tools
├── default.nix # Aggregates coding modules
├── editors.nix
├── opencode.nix # OpenCode non-agent config
└── agents/ # Per-tool agent deployment
├── default.nix
├── opencode.nix
├── claude-code.nix
└── pi.nix
```
## Importing Modules
### NixOS Modules
#### Import All Modules
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
}
```
#### Import Specific Module
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.mem0
];
}
```
#### Import from Local Path
```nix
{config, ...}: {
imports = [
./modules/nixos/mem0.nix
];
}
```
### Home Manager Modules
#### Import All Modules
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
}
```
#### Import Specific Module
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.ports
];
}
```
#### Import Category
```nix
{config, ...}: {
imports = [
# Import all CLI modules
m3ta-nixpkgs.homeManagerModules.cli.zellij-ps
];
}
```
## Available Modules
### NixOS Modules
#### `m3ta.ports`
Port management across hosts.
```nix
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
hostOverrides.laptop = {
nginx = 8080;
};
currentHost = config.networking.hostName;
};
```
**Documentation**: [Port Management Guide](./port-management.md)
#### `m3ta.mem0`
Mem0 REST API server for AI memory.
```nix
m3ta.mem0 = {
enable = true;
port = 8000;
llm = {
provider = "openai";
apiKeyFile = "/run/secrets/openai-api-key";
model = "gpt-4o-mini";
};
vectorStore = {
provider = "qdrant";
config = {
host = "localhost";
port = 6333;
};
};
};
```
**Documentation**: [mem0 Module](../modules/nixos/mem0.md)
### Home Manager Modules
#### `m3ta.ports`
Port management (similar to NixOS, with `generateEnvVars`).
```nix
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
};
generateEnvVars = true;
currentHost = config.networking.hostName;
};
```
**Documentation**: [Port Management Guide](./port-management.md)
#### `cli.zellij-ps`
Zellij project switcher for quickly navigating between project folders.
```nix
cli.zellij-ps = {
enable = true;
package = pkgs.zellij-ps;
};
```
**Documentation**: [zellij-ps Module](../modules/home-manager/cli/zellij-ps.md)
#### `coding.editors`
Editor configurations.
```nix
m3ta.coding.editors = {
enable = true;
neovim.enable = true;
zed.enable = true;
};
```
**Documentation**: [Editors Module](../modules/home-manager/coding/editors.md)
### `coding.opencode`
OpenCode AI coding assistant (non-agent config: theme, formatter, plugins).
```nix
coding.opencode = {
enable = true;
ohMyOpencodeSettings = {
agents.sisyphus.model = "anthropic/claude-opus-4-5";
};
extraSettings = {
provider.anthropic.name = "Anthropic";
};
};
```
### `coding.agents.opencode`
OpenCode agent deployment from canonical TOML definitions.
```nix
coding.agents.opencode = {
enable = true;
agentsInput = inputs.agents;
modelOverrides = {
chiron = "anthropic/claude-sonnet-4";
};
externalSkills = [
{ src = inputs.skills-anthropic; }
];
};
```
### `coding.agents.claude-code`
Claude Code agent deployment from canonical TOML definitions.
```nix
coding.agents.claude-code = {
enable = true;
agentsInput = inputs.agents;
};
```
### `coding.agents.pi`
Pi agent deployment from canonical TOML definitions.
```nix
coding.agents.pi = {
enable = true;
agentsInput = inputs.agents;
};
```
## Common Patterns
### Module Configuration
All modules follow this pattern:
```nix
{ config, lib, pkgs, ... }:
with lib; let
cfg = config.m3ta.myModule;
in {
options.m3ta.myModule = {
enable = mkEnableOption "description";
# ... other options
};
config = mkIf cfg.enable {
# ... configuration
};
}
```
### Conditional Configuration
Use `mkIf` to conditionally apply config:
```nix
config = mkIf cfg.enable {
# Only applied when cfg.enable = true
services.my-service = {
enable = true;
};
}
```
### Multiple Conditions
Use `mkMerge` for multiple conditions:
```nix
config = mkMerge [
(mkIf cfg.feature1.enable {
# Applied when feature1 is enabled
})
(mkIf cfg.feature2.enable {
# Applied when feature2 is enabled
})
];
```
### Optional Dependencies
```nix
options.m3ta.myModule = {
enable = mkEnableOption "my module";
package = mkOption {
type = types.package;
default = pkgs.defaultPackage;
};
};
config = mkIf cfg.enable {
services.my-service = {
package = cfg.package;
};
};
```
## Configuration Examples
### Minimal NixOS Configuration
```nix
{pkgs, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
m3ta.ports = {
enable = true;
definitions = {
my-service = 8080;
};
currentHost = "laptop";
};
services.my-custom-service = {
enable = true;
port = config.m3ta.ports.get "my-service";
};
}
```
### Full NixOS Configuration
```nix
{config, pkgs, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
# Port management
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
mem0 = 8000;
};
hostOverrides.laptop = {
nginx = 8080;
mem0 = 8081;
};
currentHost = config.networking.hostName;
};
# Mem0 service
m3ta.mem0 = {
enable = true;
port = config.m3ta.ports.get "mem0";
llm = {
provider = "openai";
apiKeyFile = "/run/secrets/openai-api-key";
};
vectorStore = {
provider = "qdrant";
config = {
host = "localhost";
port = 6333;
};
};
};
# Nginx
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
# Grafana
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
}
```
### Minimal Home Manager Configuration
```nix
{pkgs, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
};
currentHost = "desktop";
};
home.sessionVariables = {
DEV_PORT = toString (config.m3ta.ports.get "dev-server");
};
}
```
### Full Home Manager Configuration
```nix
{config, pkgs, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
# Port management
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
nextjs = 3001;
vite = 5173;
};
hostOverrides.laptop = {
vite = 5174;
};
currentHost = config.networking.hostName;
};
# CLI tools
cli.zellij-ps = {
enable = true;
};
# Coding tools
coding.editors = {
enable = true;
neovim.enable = true;
};
# Packages
home.packages = with pkgs; [
code2prompt
zellij-ps
];
# Environment variables
home.sessionVariables = {
EDITOR = "nvim";
DEV_SERVER_PORT = toString (config.m3ta.ports.get "dev-server");
};
}
```
## Module Options Reference
### Standard Options
All modules typically include:
| Option | Type | Description |
|---------|-------|-------------|
| `enable` | `boolean` | Enable the module |
| `package` | `package` | Custom package to use |
| `extraConfig` | `attrs` | Additional configuration |
### Port Management Options
| Option | Type | Description |
|---------|-------|-------------|
| `definitions` | `attrsOf int` | Default port definitions |
| `hostOverrides` | `attrsOf attrs` | Host-specific overrides |
| `currentHost` | `string` | Current hostname |
| `generateEnvVars` | `boolean` | Generate environment variables (HM only) |
## Combining with Other Flakes
### Using Multiple Module Sources
```nix
{config, ...}: {
imports = [
# m3ta-nixpkgs modules
m3ta-nixpkgs.nixosModules.default
# Other flake modules
inputs.impermanence.nixosModules.impermanence
inputs.sops-nix.nixosModules.sops
];
# Configure all modules
m3ta.ports = {
enable = true;
definitions = {nginx = 80;};
currentHost = config.networking.hostName;
};
environment.persistence = {
"/persist" = {
directories = ["/var/lib/mem0"];
};
};
}
```
### Using with Secrets
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
inputs.sops-nix.nixosModules.sops
];
sops.secrets = {
openai-api-key = {};
};
m3ta.mem0 = {
enable = true;
llm = {
apiKeyFile = config.sops.secrets.openai-api-key.path;
};
};
}
```
## Troubleshooting
### Module Not Found
Error: `error: The option 'm3ta.mymodule' does not exist`
**Solutions**:
1. Make sure you imported the module:
```nix
imports = [
m3ta-nixpkgs.nixosModules.default
];
```
2. Check module name is correct
```nix
# Correct
m3ta.mem0.enable = true;
# Wrong
m3ta.mymodule.enable = true; # Doesn't exist
```
### Option Type Mismatch
Error: `type mismatch at 'm3ta.mymodule.enable', expected a boolean but got a list`
**Solution**: Check option types in documentation
```nix
# Correct
m3ta.mymodule.enable = true;
# Wrong
m3ta.mymodule.enable = [true]; # Should be boolean
```
### Port Not Defined
Error: `Service "foo" not defined`
**Solution**: Add to port definitions
```nix
m3ta.ports = {
definitions = {
foo = 8080; # Add this
};
};
```
## Best Practices
### Use Namespaces
Always use the `m3ta.*` namespace:
```nix
# Good
m3ta.mem0.enable = true;
# Bad (potential conflicts)
mem0.enable = true;
```
### Document Your Configuration
Add comments explaining module usage:
```nix
# Port management for multi-host setup
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
hostOverrides.laptop = {
nginx = 8080; # Use different port on laptop
};
currentHost = config.networking.hostName;
};
# Mem0 AI memory service
m3ta.mem0 = {
enable = true;
port = config.m3ta.ports.get "mem0";
};
```
### Test Configuration
```bash
# Test NixOS configuration without applying
sudo nixos-rebuild test --flake .#hostname
# Check configuration
nix flake check
# Show all options
nix eval .#nixosConfigurations.hostname.config.m3ta --apply builtins.attrNames
```
## Next Steps
- [Port Management](./port-management.md) - Detailed port management guide
- [Adding Packages](./adding-packages.md) - How to add new packages
- [Adding Modules](./adding-modules.md) - How to add new NixOS or Home Manager modules
- [Templates](../templates.md) - Boilerplate for new packages and modules
- [Architecture](../ARCHITECTURE.md) - Understanding module structure
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines
@@ -0,0 +1,219 @@
# rofi-project-opener Module
Home Manager module for configuring the rofi-project-opener package.
## Overview
This module provides declarative configuration for rofi-project-opener, a Rofi-based project launcher. It generates the necessary configuration files and installs the package.
## Quick Start
```nix
{config, pkgs, ...}: {
cli.rofi-project-opener = {
enable = true;
projectDirs = {
dev = { path = "~/dev"; };
work = { path = "~/work"; args = "--agent work-assistant"; };
};
};
}
```
## Options
### `cli.rofi-project-opener.enable`
Whether to enable rofi-project-opener.
**Type:** `boolean`
**Default:** `false`
### `cli.rofi-project-opener.projectDirs`
Attribute set of base directories to scan for project subdirectories.
**Type:** `attrsOf (submodule)`
Each entry is a submodule with:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `path` | `str` | required | Base directory path (supports `~`) |
| `args` | `str` | `""` | Arguments to pass to command |
**Default:**
```nix
{
dev = { path = "~/dev"; };
projects = { path = "~/projects"; };
}
```
**Example:**
```nix
projectDirs = {
nixpkgs = { path = "~/p/NIX"; args = "--agent nix-expert"; };
chat = { path = "~/p/CHAT"; args = "--agent chiron"; };
dev = { path = "~/dev"; };
work = { path = "~/work"; args = "--profile work"; };
};
```
### `cli.rofi-project-opener.terminal`
Terminal emulator to use for launching projects.
**Type:** `either str package`
**Default:** `"kitty"`
**Examples:**
```nix
# Using a package
terminal = pkgs.kitty;
terminal = pkgs.alacritty;
# Using a string (must be in PATH)
terminal = "kitty";
terminal = "wezterm";
```
### `cli.rofi-project-opener.terminalCommand`
Command to run in the terminal after navigating to the project directory.
**Type:** `str`
**Default:** `""` (runs `opencode` with args)
**Placeholders:**
- `%s` - Project path
- `%a` - Project args (from `projectDirs.<name>.args`)
**Examples:**
```nix
# Default behavior - run opencode with project args
terminalCommand = "";
# Explicit opencode with args
terminalCommand = "opencode %a";
# Different editor
terminalCommand = "nvim";
# VSCode with path
terminalCommand = "code %s";
# Custom application
terminalCommand = "my-dev-tool --project %s %a";
```
### `cli.rofi-project-opener.rofiPrompt`
Prompt text displayed in the Rofi menu.
**Type:** `str`
**Default:** `"Select project"`
### `cli.rofi-project-opener.rofiArgs`
Arguments to pass to Rofi.
**Type:** `listOf str`
**Default:** `["-dmenu" "-i"]`
**Example:**
```nix
rofiArgs = ["-dmenu" "-i" "-theme" "gruvbox" "-width" "50"];
```
## Generated Files
The module generates these configuration files:
### `~/.config/rofi-project-opener/projects.json`
JSON file containing project directories:
```json
{
"dev": {"path": "~/dev", "args": ""},
"work": {"path": "~/work", "args": "--agent work-assistant"}
}
```
### `~/.config/rofi-project-opener/config`
Shell configuration file:
```bash
TERMINAL="/nix/store/.../bin/kitty"
TERMINAL_CMD="opencode %a"
ROFI_PROMPT="Select project"
ROFI_ARGS="-dmenu -i"
```
## Full Example
```nix
{config, pkgs, ...}: {
imports = [m3ta-nixpkgs.homeManagerModules.default];
cli.rofi-project-opener = {
enable = true;
# Project directories with optional args
projectDirs = {
nixpkgs = {
path = "~/p/NIX";
args = "";
};
chat = {
path = "~/p/CHAT";
args = "--agent chiron";
};
dev = {
path = "~/dev";
args = "";
};
};
# Terminal configuration
terminal = pkgs.kitty;
terminalCommand = "opencode %a";
# Rofi configuration
rofiPrompt = "Open Project";
rofiArgs = ["-dmenu" "-i" "-theme" "nord"];
};
}
```
## Usage
After enabling, run:
```bash
rofi-project-opener
```
Or bind to a keyboard shortcut in your window manager:
**Hyprland:**
```nix
wayland.windowManager.hyprland.settings.bind = [
"$mod, P, exec, rofi-project-opener"
];
```
**Sway:**
```nix
wayland.windowManager.sway.config.keybindings = {
"${modifier}+p" = "exec rofi-project-opener";
};
```
## Related
- [rofi-project-opener Package](../../../packages/rofi-project-opener.md) - Package documentation
- [zellij-ps Module](./zellij-ps.md) - Similar project switcher for Zellij
- [Home Manager Overview](../overview.md) - All Home Manager modules
+312
View File
@@ -0,0 +1,312 @@
# stt-ptt Home Manager Module
Push to Talk Speech to Text for Home Manager.
## Overview
This module configures stt-ptt, a push-to-talk speech-to-text tool using whisper.cpp. It handles model downloads, environment configuration, and package installation.
## Quick Start
```nix
{config, ...}: {
imports = [m3ta-nixpkgs.homeManagerModules.default];
cli.stt-ptt = {
enable = true;
};
}
```
This will:
- Install stt-ptt with default whisper-cpp
- Download the `ggml-large-v3-turbo` model on first activation
- Set environment variables for model path and notification timeout
## Module Options
### `cli.stt-ptt.enable`
Enable the stt-ptt module.
- Type: `boolean`
- Default: `false`
### `cli.stt-ptt.whisperPackage`
The whisper-cpp package to use for transcription.
- Type: `package`
- Default: `pkgs.whisper-cpp`
**Pre-built variants:**
```nix
# CPU (default)
whisperPackage = pkgs.whisper-cpp;
# Vulkan GPU acceleration (pre-built)
whisperPackage = pkgs.whisper-cpp-vulkan;
```
**Override options** (can be combined):
| Option | Description |
|--------|-------------|
| `cudaSupport` | NVIDIA CUDA acceleration |
| `rocmSupport` | AMD ROCm acceleration |
| `vulkanSupport` | Vulkan GPU acceleration |
| `coreMLSupport` | Apple CoreML (macOS only) |
| `metalSupport` | Apple Metal (macOS ARM only) |
```nix
# NVIDIA CUDA support
whisperPackage = pkgs.whisper-cpp.override { cudaSupport = true; };
# AMD ROCm support
whisperPackage = pkgs.whisper-cpp.override { rocmSupport = true; };
# Vulkan support (manual override)
whisperPackage = pkgs.whisper-cpp.override { vulkanSupport = true; };
```
### `cli.stt-ptt.model`
The Whisper model to use. Models are automatically downloaded from HuggingFace on first activation.
- Type: `string`
- Default: `"ggml-large-v3-turbo"`
Available models (sorted by size):
| Model | Size | Notes |
|-------|------|-------|
| `ggml-tiny` | 75MB | Fastest, lowest quality |
| `ggml-tiny.en` | 75MB | English-only, slightly faster |
| `ggml-base` | 142MB | Fast, basic quality |
| `ggml-base.en` | 142MB | English-only |
| `ggml-small` | 466MB | Balanced speed/quality |
| `ggml-small.en` | 466MB | English-only |
| `ggml-medium` | 1.5GB | Good quality |
| `ggml-medium.en` | 1.5GB | English-only |
| `ggml-large-v1` | 2.9GB | High quality (original) |
| `ggml-large-v2` | 2.9GB | High quality (improved) |
| `ggml-large-v3` | 2.9GB | Highest quality |
| `ggml-large-v3-turbo` | 1.6GB | High quality, optimized speed (recommended) |
Quantized versions (`q5_0`, `q5_1`, `q8_0`) are also available for reduced size.
### `cli.stt-ptt.notifyTimeout`
Notification timeout in milliseconds for the recording indicator.
- Type: `integer`
- Default: `3000`
- Example: `5000` (5 seconds), `0` (persistent)
### `cli.stt-ptt.language`
Language for speech recognition. Use "auto" for automatic language detection, or specify a language code for better accuracy.
- Type: `enum ["auto", "en", "es", "fr", "de", "it", "pt", "ru", "zh", "ja", "ko", "ar", "hi", "tr", "pl", "nl", "sv", "da", "fi", "no", "vi", "th", "id", "uk", "cs"]`
- Default: `"auto"`
**Auto-detection**: When set to "auto", whisper.cpp analyzes the audio to determine the spoken language automatically.
**Language specification**: Specifying a language code improves transcription accuracy if you know the language in advance.
```nix
# Automatic language detection (default)
language = "auto";
# Force English transcription
language = "en";
# Spanish transcription
language = "es";
```
**Common language codes:**
| Code | Language |
|------|----------|
| `en` | English |
| `es` | Spanish |
| `fr` | French |
| `de` | German |
| `zh` | Chinese |
| `ja` | Japanese |
| `ko` | Korean |
whisper.cpp supports 100+ languages. See whisper.cpp documentation for the full list.
## Usage
After enabling, bind `stt-ptt start` and `stt-ptt stop` to a key:
```bash
# Start recording
stt-ptt start
# Stop recording and transcribe (types result)
stt-ptt stop
```
### Keybinding Examples
#### Hyprland
```nix
wayland.windowManager.hyprland.settings = {
bind = [
"SUPER, V, exec, stt-ptt start"
];
bindr = [
"SUPER, V, exec, stt-ptt stop"
];
};
```
Or in `hyprland.conf`:
```conf
# Press to start recording, release to transcribe
bind = SUPER, V, exec, stt-ptt start
bindr = SUPER, V, exec, stt-ptt stop
```
#### Sway
```conf
bindsym --no-repeat $mod+v exec stt-ptt start
bindsym --release $mod+v exec stt-ptt stop
```
## Configuration Examples
### Basic Setup
```nix
cli.stt-ptt = {
enable = true;
};
```
### Fast English Transcription
```nix
cli.stt-ptt = {
enable = true;
model = "ggml-base.en";
notifyTimeout = 2000;
};
```
### Language-Specific Transcription
```nix
cli.stt-ptt = {
enable = true;
model = "ggml-large-v3-turbo";
language = "es"; # Force Spanish transcription
};
```
### High Quality with NVIDIA GPU
```nix
cli.stt-ptt = {
enable = true;
model = "ggml-large-v3";
whisperPackage = pkgs.whisper-cpp.override { cudaSupport = true; };
};
```
### Vulkan GPU Acceleration
```nix
cli.stt-ptt = {
enable = true;
model = "ggml-large-v3-turbo";
whisperPackage = pkgs.whisper-cpp-vulkan;
};
```
### AMD GPU with ROCm
```nix
cli.stt-ptt = {
enable = true;
model = "ggml-large-v3-turbo";
whisperPackage = pkgs.whisper-cpp.override { rocmSupport = true; };
};
```
### Balanced Setup
```nix
cli.stt-ptt = {
enable = true;
model = "ggml-small";
notifyTimeout = 3000;
};
```
## File Locations
| Path | Description |
|------|-------------|
| `~/.local/share/stt-ptt/models/` | Downloaded Whisper models |
| `~/.cache/stt-ptt/stt.wav` | Temporary audio recording |
| `~/.cache/stt-ptt/stt.pid` | PID file for recording process |
## Environment Variables
The module sets these automatically:
| Variable | Value |
|----------|-------|
| `STT_MODEL` | `~/.local/share/stt-ptt/models/<model>.bin` |
| `STT_LANGUAGE` | Configured language ("auto" by default) |
| `STT_NOTIFY_TIMEOUT` | Configured timeout in ms |
## Requirements
- Wayland compositor (wtype is Wayland-only)
- PipeWire for audio recording
- Desktop notification daemon
## Troubleshooting
### Model Download Failed
The model downloads on first `home-manager switch`. If it fails:
```bash
# Manual download
mkdir -p ~/.local/share/stt-ptt/models
curl -L -o ~/.local/share/stt-ptt/models/ggml-large-v3-turbo.bin \
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin
```
### Transcription Too Slow
Use a smaller model or enable GPU acceleration:
```nix
cli.stt-ptt = {
enable = true;
model = "ggml-tiny.en"; # Much faster
};
```
### Text Not Appearing
1. Ensure you're on Wayland: `echo $XDG_SESSION_TYPE`
2. Check if wtype works: `wtype "test"`
3. Some apps may need focus; try clicking the text field first
## Related
- [stt-ptt Package](../../../packages/stt-ptt.md) - Package documentation
- [Using Modules Guide](../../../guides/using-modules.md) - Module usage patterns
@@ -0,0 +1,81 @@
# zellij-ps Home Manager Module
Zellij project switcher for Home Manager.
## Overview
This module configures the zellij-ps tool, a Fish script that provides a fast, interactive way to switch between project folders in Zellij terminal multiplexer sessions.
## Quick Start
```nix
{config, ...}: {
imports = [m3ta-nixpkgs.homeManagerModules.default];
cli.zellij-ps = {
enable = true;
};
}
```
## Module Options
### `cli.zellij-ps.enable`
Enable zellij-ps module.
- Type: `boolean`
- Default: `false`
### `cli.zellij-ps.package`
Custom package to use.
- Type: `package`
- Default: `pkgs.zellij-ps`
## Usage
After enabling, zellij-ps will be available in your path:
```bash
# Run from outside Zellij to start a project session
zellij-ps
# Or pass a project path directly
zellij-ps ~/projects/my-project
```
### Basic Usage
1. Set `$PROJECT_FOLDERS` in your shell config (e.g., `~/projects:~/code`)
2. Run `zellij-ps` from outside a Zellij session
3. Use fzf to select a project from your configured folders
4. Zellij will create or attach to a session for that project
## Configuration
### Custom Package
Use a custom or modified package:
```nix
cli.zellij-ps = {
enable = true;
package = pkgs.callPackage ./my-zellij-ps {};
};
```
## Dependencies
The module ensures these are installed:
- `fish` - Shell for script execution
- `fd` - Fast file search
- `fzf` - Fuzzy finder
- `zellij` - Terminal multiplexer
## Related
- [zellij-ps Package](../../packages/zellij-ps.md) - Package documentation
- [Using Modules Guide](../../guides/using-modules.md) - Module usage patterns
+317
View File
@@ -0,0 +1,317 @@
# editors Home Manager Module
Editor configurations for Home Manager.
## Overview
This module provides pre-configured settings for various code editors, making it easy to set up your development environment.
## Quick Start
```nix
{config, ...}: {
imports = [m3ta-nixpkgs.homeManagerModules.default];
m3ta.coding.editors = {
enable = true;
neovim.enable = true;
zed.enable = true;
};
}
```
## Module Options
### `m3ta.coding.editors.enable`
Enable the editors module.
- Type: `boolean`
- Default: `false`
### `m3ta.coding.editors.neovim.enable`
Enable Neovim configuration.
- Type: `boolean`
- Default: `false`
### `m3ta.coding.editors.neovim.package`
Custom Neovim package.
- Type: `package`
- Default: `pkgs.neovim`
### `m3ta.coding.editors.zed.enable`
Enable Zed editor configuration.
- Type: `boolean`
- Default: `false`
### `m3ta.coding.editors.zed.package`
Custom Zed package.
- Type: `package`
- Default: `pkgs.zed`
## Supported Editors
### Neovim
Neovim is a highly extensible Vim-based text editor.
```nix
m3ta.coding.editors = {
enable = true;
neovim = {
enable = true;
package = pkgs.neovim;
};
}
```
**Features**:
- Vim-style editing
- Plugin system
- Lua scripting
- Fast performance
- Built-in LSP support
**Configuration**: The module provides sensible defaults. You can customize by adding your own configuration.
### Zed
Zed is a high-performance, multiplayer code editor.
```nix
m3ta.coding.editors = {
enable = true;
zed = {
enable = true;
package = pkgs.zed;
};
}
```
**Features**:
- Fast startup
- Built-in collaboration
- AI assistance (optional)
- Modern UI
- Low memory usage
**Configuration**: Zed uses JSON configuration files that can be customized.
## Usage Examples
### Minimal Neovim Setup
```nix
{config, ...}: {
m3ta.coding.editors = {
enable = true;
neovim.enable = true;
};
}
```
### Minimal Zed Setup
```nix
{config, ...}: {
m3ta.coding.editors = {
enable = true;
zed.enable = true;
};
}
```
### Multiple Editors
```nix
{config, ...}: {
m3ta.coding.editors = {
enable = true;
neovim.enable = true;
zed.enable = true;
};
}
```
### Custom Package
```nix
{config, ...}: {
m3ta.coding.editors = {
enable = true;
neovim = {
enable = true;
package = pkgs.neovim-unwrapped; # Use unwrapped version
};
};
}
```
## Configuration Files
### Neovim
The module sets up Neovim configuration in:
```
~/.config/nvim/
```
You can extend it with:
```nix
{config, ...}: {
xdg.configFile."nvim/init.lua".text = ''
-- Your custom Neovim configuration
'';
}
```
### Zed
Zed configuration is in:
```
~/.config/zed/settings.json
```
You can customize it with:
```nix
{config, ...}: {
xdg.configFile."zed/settings.json".text = builtins.toJSON {
# Your custom Zed settings
};
}
```
## Migration Guide
### From Manual Configuration
If you have existing editor configurations, you can:
1. Backup your current config
2. Enable the module
3. Test it out
4. Gradually migrate custom settings
**Backup**:
```bash
# Backup Neovim
cp -r ~/.config/nvim ~/.config/nvim.backup
# Backup Zed
cp -r ~/.config/zed ~/.config/zed.backup
```
### From Other Editors
**Vim to Neovim**:
- Most Vim configurations work with Neovim
- Enable module and test
- Migrate plugins to modern Lua versions
**VSCode to Zed**:
- Zed has built-in keybinding presets
- Enable module and check keybindings
- Adjust as needed
## Keybindings
### Neovim
Default keybindings (Vim-style):
| Mode | Key | Action |
|-------|------|---------|
| Normal | `i` | Enter insert mode |
| Normal | `ESC` | Exit insert mode |
| Normal | `:w` | Save |
| Normal | `:q` | Quit |
| Normal | `u` | Undo |
| Normal | `Ctrl+r` | Redo |
### Zed
Default keybindings:
| Mode | Key | Action |
|-------|------|---------|
| General | `Ctrl+S` | Save |
| General | `Ctrl+P` | Command palette |
| General | `Ctrl+Shift+P` | File palette |
| Navigation | `Ctrl+B` | Toggle sidebar |
| Navigation | `Ctrl+Shift+B` | Toggle activity bar |
## Plugins and Extensions
### Neovim
The module provides a base. You can add plugins using:
```nix
{pkgs, ...}: {
programs.neovim.plugins = with pkgs.vimPlugins; [
nvim-lspconfig
nvim-treesitter
telescope-nvim
];
}
```
### Zed
Zed extensions are managed through the editor:
1. Open Zed
2. Go to Extensions (Ctrl+Shift+X)
3. Browse and install extensions
## Troubleshooting
### Editor Not Found
Ensure the editor package is installed:
```bash
# Check Neovim
which nvim
# Check Zed
which zed
```
### Configuration Not Applied
Check if the module is enabled:
```bash
# Check Home Manager state
home-manager show
# View current config
nix eval .#homeConfigurations.username.config.m3ta.coding.editors --apply builtins.attrNames
```
### Conflicts with Existing Config
If you have existing configuration:
1. Backup current config
2. Test module with fresh config
3. Gradually add custom settings
## Related
- [Using Modules Guide](../../guides/using-modules.md) - How to use modules
- [Adding Packages](../../guides/adding-packages.md) - How to add new packages
+206
View File
@@ -0,0 +1,206 @@
# Home Manager Modules Overview
Overview of available Home Manager modules in m3ta-nixpkgs.
## Available Modules
### Core Modules
- [ports](./ports.md) - Port management across hosts
### CLI Modules (`cli/`)
- [zellij-ps](./cli/zellij-ps.md) - Zellij project switcher
### Coding Modules (`coding/`)
- [editors](./coding/editors.md) - Editor configurations
## Importing Modules
### Import All Modules
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
}
```
### Import Specific Module
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.ports
m3ta-nixpkgs.homeManagerModules.zellij-ps
];
}
```
### Import Category
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.cli.zellij-ps
m3ta-nixpkgs.homeManagerModules.coding.editors
];
}
```
## Module Namespace
All Home Manager modules use the `m3ta.*` namespace:
```nix
# Port management
m3ta.ports = {
enable = true;
definitions = {dev-server = 3000;};
};
# CLI tools
cli.zellij-ps = {
enable = true;
};
# Coding tools
coding.editors = {
enable = true;
neovim.enable = true;
};
```
## Module Categories
### Core
Essential modules for all users:
- **ports** - Port management with optional environment variable generation
### CLI (`cli/`)
Command-line interface tools and utilities:
- **zellij-ps** - Project switcher for Zellij terminal multiplexer
### Coding (`coding/`)
Development tools and configurations:
- **editors** - Editor configurations (Neovim, Zed, etc.)
## Integration Examples
### With NixOS
```nix
{config, ...}: {
# NixOS modules
imports = [
m3ta-nixpkgs.nixosModules.default
];
# Home Manager integration
home-manager.users.myusername = {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
};
currentHost = config.networking.hostName;
};
};
}
```
### Standalone Home Manager
```nix
{config, pkgs, ...}: {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
};
currentHost = "desktop";
};
cli.zellij-ps = {
enable = true;
};
coding.editors = {
enable = true;
neovim.enable = true;
};
}
```
## Module Locations
### Core
- `modules/home-manager/ports.nix` - Port management module
### CLI
- `modules/home-manager/cli/default.nix` - CLI module aggregator
- `modules/home-manager/cli/zellij-ps.nix` - Zellij project switcher
### Coding
- `modules/home-manager/coding/default.nix` - Coding module aggregator
- `modules/home-manager/coding/editors.nix` - Editor configurations
## Adding New Modules
### Core Module
1. Create: `modules/home-manager/my-module.nix`
2. Add to `modules/home-manager/default.nix`
### CLI Module
1. Create: `modules/home-manager/cli/my-tool.nix`
2. Add to `modules/home-manager/cli/default.nix`
### Coding Module
1. Create: `modules/home-manager/coding/my-tool.nix`
2. Add to `modules/home-manager/coding/default.nix`
### Module Template
```nix
{ config, lib, pkgs, ... }:
with lib; let
cfg = config.m3ta.category.myModule;
in {
options.m3ta.category.myModule = {
enable = mkEnableOption "my module";
# ... options
};
config = mkIf cfg.enable {
# Configuration
};
}
```
## Related
- [Using Modules Guide](../../guides/using-modules.md) - How to use modules
- [NixOS Modules](./nixos/overview.md) - System-level modules
- [Port Management Guide](../../guides/port-management.md) - Detailed port management
+272
View File
@@ -0,0 +1,272 @@
# ports Home Manager Module
Port management module for Home Manager.
## Overview
This module provides centralized port management for user-level services, similar to the NixOS version but with additional support for generating environment variables.
See [Port Management Guide](../../guides/port-management.md) for detailed usage.
## Quick Start
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
# Define default ports
definitions = {
dev-server = 3000;
nextjs = 3001;
vite = 5173;
};
# Host-specific overrides
hostOverrides = {
laptop = {
vite = 5174;
};
};
# Current host
currentHost = "desktop";
# Generate environment variables (Home Manager only)
generateEnvVars = true;
};
}
```
## Module Options
### `m3ta.ports.enable`
Enable port management.
- Type: `boolean`
- Default: `false`
### `m3ta.ports.definitions`
Default port definitions.
- Type: `attrsOf int`
- Default: `{}`
Example:
```nix
definitions = {
dev-server = 3000;
nextjs = 3001;
vite = 5173;
};
```
### `m3ta.ports.hostOverrides`
Host-specific port overrides.
- Type: `attrsOf (attrsOf int)`
- Default: `{}`
Example:
```nix
hostOverrides = {
laptop = {
vite = 5174;
};
desktop = {
vite = 5173;
};
};
```
### `m3ta.ports.currentHost`
Current hostname.
- Type: `string`
- Example: `"desktop"`
### `m3ta.ports.generateEnvVars`
Generate environment variables from ports.
- Type: `boolean`
- Default: `false`
- Home Manager only
When enabled, generates environment variables like:
```bash
PORT_DEV_SERVER=3000
PORT_NEXTJS=3001
PORT_VITE=5173
```
## Functions
### `config.m3ta.ports.get "service"`
Get port for a service with host-specific override.
```nix
home.sessionVariables = {
DEV_PORT = toString (config.m3ta.ports.get "dev-server");
};
```
### `config.m3ta.ports.getHostPorts "hostname"`
Get all ports for a specific host.
```nix
laptopPorts = config.m3ta.ports.getHostPorts "laptop";
# Returns: { dev-server = 3000; vite = 5174; ... }
```
### `config.m3ta.ports.listServices`
List all defined service names.
```nix
allServices = config.m3ta.ports.listServices;
# Returns: ["dev-server" "nextjs" "vite"]
```
## Environment Variables
When `generateEnvVars = true`, the following environment variables are generated:
```
PORT_<SERVICE_UPPERCASE>=<port_number>
```
Example:
```nix
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
nextjs = 3001;
};
generateEnvVars = true;
};
```
Generates:
```bash
PORT_DEV_SERVER=3000
PORT_NEXTJS=3001
```
You can then use these in scripts:
```bash
#!/usr/bin/env bash
# Use environment variable directly
npm start --port=$PORT_DEV_SERVER
```
## Usage Examples
### Basic Usage
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
};
currentHost = "desktop";
};
home.sessionVariables = {
DEV_PORT = toString (config.m3ta.ports.get "dev-server");
};
}
```
### With Environment Variables
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
nextjs = 3001;
vite = 5173;
};
currentHost = "desktop";
generateEnvVars = true;
};
# Now available as environment variables
# PORT_DEV_SERVER=3000
# PORT_NEXTJS=3001
# PORT_VITE=5173
}
```
### With Multi-Host Setup
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
vite = 5173;
};
hostOverrides = {
laptop = {
vite = 5174;
};
desktop = {
vite = 5173;
};
};
currentHost = config.networking.hostName;
generateEnvVars = true;
};
}
```
### With Shell Scripts
Create `~/.config/zellij/scripts/dev.ksh`:
```ksh
#!/usr/bin/env ksh
# Start dev server using environment variable
cd ~/projects/my-app
npm start --port=$PORT_DEV_SERVER
```
## Difference from NixOS Module
The Home Manager version has one additional feature:
### `generateEnvVars`
Not available in NixOS module. Generates environment variables for all defined ports:
```nix
# Home Manager
m3ta.ports.generateEnvVars = true; # Available
# NixOS
# Not available
```
## Related
- [Port Management Guide](../../guides/port-management.md) - Detailed guide
- [NixOS Ports Module](../nixos/ports.md) - System-level port management
+508
View File
@@ -0,0 +1,508 @@
# mem0 NixOS Module
Mem0 REST API server module for AI memory management.
## Overview
This module provides a systemd service for the Mem0 REST API server, enabling AI agents to maintain persistent memory across conversations.
## Quick Start
```nix
{config, ...}: {
imports = [m3ta-nixpkgs.nixosModules.mem0];
m3ta.mem0 = {
enable = true;
port = 8000;
llm = {
provider = "openai";
apiKeyFile = "/run/secrets/openai-api-key";
model = "gpt-4o-mini";
};
vectorStore = {
provider = "qdrant";
config = {
host = "localhost";
port = 6333;
};
};
};
}
```
## Module Options
### `m3ta.mem0.enable`
Enable the Mem0 REST API server.
- Type: `boolean`
- Default: `false`
### `m3ta.mem0.package`
The mem0 package to use.
- Type: `package`
- Default: `pkgs.mem0`
### `m3ta.mem0.host`
Host address to bind the server to.
- Type: `string`
- Default: `"127.0.0.1"`
### `m3ta.mem0.port`
Port to run the REST API server on.
- Type: `port`
- Default: `8000`
### `m3ta.mem0.workers`
Number of worker processes.
- Type: `integer`
- Default: `1`
### `m3ta.mem0.logLevel`
Logging level for the server.
- Type: `enum` ["critical" "error" "warning" "info" "debug" "trace"]
- Default: `"info"`
### `m3ta.mem0.stateDir`
Directory to store mem0 data and state.
- Type: `path`
- Default: `"/var/lib/mem0"`
### `m3ta.mem0.user`
User account under which mem0 runs.
- Type: `string`
- Default: `"mem0"`
### `m3ta.mem0.group`
Group under which mem0 runs.
- Type: `string`
- Default: `"mem0"`
### `m3ta.mem0.environmentFile`
Environment file containing additional configuration.
- Type: `nullOr path`
- Default: `null`
## LLM Configuration
### `m3ta.mem0.llm.provider`
LLM provider to use.
- Type: `enum` ["openai" "anthropic" "azure" "groq" "together" "ollama" "litellm"]
- Default: `"openai"`
### `m3ta.mem0.llm.model`
Model name to use.
- Type: `string`
- Default: `"gpt-4o-mini"`
### `m3ta.mem0.llm.apiKeyFile`
Path to file containing the API key.
- Type: `nullOr path`
- Default: `null`
- Example: `"/run/secrets/openai-api-key"`
### `m3ta.mem0.llm.temperature`
Temperature parameter for LLM generation.
- Type: `nullOr float`
- Default: `null`
### `m3ta.mem0.llm.maxTokens`
Maximum tokens for LLM generation.
- Type: `nullOr int`
- Default: `null`
### `m3ta.mem0.llm.extraConfig`
Additional LLM configuration options.
- Type: `attrs`
- Default: `{}`
## Vector Store Configuration
### `m3ta.mem0.vectorStore.provider`
Vector database provider.
- Type: `enum` ["qdrant" "chroma" "pinecone" "weaviate" "faiss" "pgvector" "redis" "elasticsearch" "milvus"]
- Default: `"qdrant"`
### `m3ta.mem0.vectorStore.config`
Configuration for the vector store.
- Type: `attrs`
- Default: `{}`
Example for Qdrant:
```nix
vectorStore.config = {
host = "localhost";
port = 6333;
collection_name = "mem0_memories";
};
```
Example for pgvector:
```nix
vectorStore.config = {
host = "localhost";
port = 5432;
dbname = "postgres";
user = "postgres";
password = "postgres";
};
```
## Embedder Configuration
### `m3ta.mem0.embedder.provider`
Embedding model provider.
- Type: `nullOr (enum` ["openai" "huggingface" "ollama" "vertexai"])
- Default: `null`
### `m3ta.mem0.embedder.model`
Embedding model name.
- Type: `nullOr string`
- Default: `null`
### `m3ta.mem0.embedder.config`
Configuration for the embedder.
- Type: `attrs`
- Default: `{}`
## Usage Examples
### Minimal Configuration
```nix
{config, ...}: {
m3ta.mem0 = {
enable = true;
};
}
```
### With OpenAI
```nix
{config, ...}: {
m3ta.mem0 = {
enable = true;
llm = {
provider = "openai";
apiKeyFile = "/run/secrets/openai-api-key";
model = "gpt-4";
};
};
}
```
### With Local LLM (Ollama)
```nix
{config, ...}: {
m3ta.mem0 = {
enable = true;
llm = {
provider = "ollama";
model = "llama2";
};
};
}
```
### With Port Management
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
mem0 = 8000;
};
currentHost = config.networking.hostName;
};
m3ta.mem0 = {
enable = true;
port = config.m3ta.ports.get "mem0";
};
}
```
### With Qdrant
```nix
{config, ...}: {
m3ta.mem0 = {
enable = true;
vectorStore = {
provider = "qdrant";
config = {
host = "localhost";
port = 6333;
};
};
};
}
services.qdrant = {
enable = true;
port = 6333;
};
```
### With Secrets (agenix)
```nix
{config, ...}: {
age.secrets.openai-api-key = {
file = ./secrets/openai-api-key.age;
};
m3ta.mem0 = {
enable = true;
llm = {
apiKeyFile = config.age.secrets.openai-api-key.path;
};
};
}
```
## Service Management
### Start/Stop/Restart
```bash
# Start service
sudo systemctl start mem0
# Stop service
sudo systemctl stop mem0
# Restart service
sudo systemctl restart mem0
# Check status
sudo systemctl status mem0
```
### View Logs
```bash
# View logs
sudo journalctl -u mem0 -f
# View last 100 lines
sudo journalctl -u mem0 -n 100
```
### Service File
The module creates a systemd service at `/etc/systemd/system/mem0.service` with:
- Security hardening enabled
- Automatic restart on failure
- Proper user/group setup
## API Usage
### Add Memory
```bash
curl -X POST http://localhost:8000/v1/memories \
-H "Content-Type: application/json" \
-d '{
"content": "User prefers coffee over tea",
"metadata": {"user_id": "123"}
}'
```
### Search Memories
```bash
curl http://localhost:8000/v1/memories/search?q=coffee
```
### Update Memory
```bash
curl -X PATCH http://localhost:8000/v1/memories/memory_id \
-H "Content-Type: application/json" \
-d '{
"content": "User prefers coffee over tea, but also likes chai"
}'
```
### Delete Memory
```bash
curl -X DELETE http://localhost:8000/v1/memories/memory_id
```
## Dependencies
### Required Services
Depending on your configuration, you may need:
- **qdrant** service (if using qdrant vector store)
- **postgresql** with pgvector (if using pgvector)
- **chroma** service (if using chroma)
- **ollama** (if using local LLMs)
### Example: Qdrant
```nix
services.qdrant = {
enable = true;
port = 6333;
};
```
### Example: PostgreSQL
```nix
services.postgresql = {
enable = true;
enableTCPIP = true;
package = pkgs.postgresql_15;
extensions = ["pgvector"];
settings = {
port = 5432;
};
};
```
## Firewall
The module automatically opens the firewall port if binding to non-localhost addresses:
```nix
# Opens port if host is not "127.0.0.1" or "localhost"
m3ta.mem0 = {
enable = true;
host = "0.0.0.0"; # Binds to all interfaces
port = 8000;
};
# Firewall automatically opens port 8000
```
## Security
### User/Group
Creates dedicated user and group:
- User: `mem0`
- Group: `mem0`
- Home: `/var/lib/mem0`
### Hardening
Systemd service includes security hardening:
- `NoNewPrivileges`
- `PrivateTmp`
- `ProtectSystem=strict`
- `ProtectHome=true`
- `RestrictRealtime=true`
- `RestrictNamespaces=true`
- `LockPersonality=true`
### Secrets
Use `apiKeyFile` for API keys instead of plain text:
```nix
# Good
llm.apiKeyFile = "/run/secrets/openai-api-key";
# Bad (insecure)
llm.apiKey = "sk-xxx";
```
## Troubleshooting
### Service Won't Start
Check logs:
```bash
sudo journalctl -u mem0 -n 50
```
Common issues:
1. **API key missing**: Ensure `apiKeyFile` exists and is readable
2. **Vector store unavailable**: Ensure qdrant/other store is running
3. **Port in use**: Check if port is available
### API Not Responding
Check service status:
```bash
sudo systemctl status mem0
# Check if port is open
ss -tuln | grep 8000
```
### Memory Issues
Increase memory limit in systemd override:
```bash
sudo systemctl edit mem0
[Service]
MemoryMax=2G
```
## Related
- [mem0 Package](../../packages/mem0.md) - Package documentation
- [Port Management Guide](../../guides/port-management.md) - Using with port management
- [Using Modules Guide](../../guides/using-modules.md) - Module usage patterns
+166
View File
@@ -0,0 +1,166 @@
# NixOS Modules Overview
Overview of available NixOS modules in m3ta-nixpkgs.
## Available Modules
- [ports](./ports.md) - Port management across hosts
- [mem0](./mem0.md) - Mem0 REST API server
## Importing Modules
### Import All Modules
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
}
```
### Import Specific Module
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.ports
m3ta-nixpkgs.nixosModules.mem0
];
}
```
## Module Namespace
All NixOS modules use the `m3ta.*` namespace:
```nix
# Port management
m3ta.ports = {
enable = true;
definitions = {nginx = 80;};
};
# Mem0 service
m3ta.mem0 = {
enable = true;
port = 8000;
};
```
## Common Patterns
### Enable Module
All modules follow the pattern:
```nix
m3ta.moduleName = {
enable = true;
# ... options
};
```
### Configuration
Modules typically provide these sections:
- `enable` - Enable/disable module
- `package` - Custom package (optional)
- Configuration options specific to module
## Integration Examples
### With Port Management
```nix
{config, ...}: {
imports = [
m3ta-nixpkgs.nixosModules.default
];
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
mem0 = 8000;
};
currentHost = config.networking.hostName;
};
m3ta.mem0 = {
enable = true;
port = config.m3ta.ports.get "mem0";
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
root /var/www;
}
'';
};
}
```
### With Home Manager
```nix
{config, ...}: {
# NixOS modules
imports = [
m3ta-nixpkgs.nixosModules.default
];
# Home Manager integration
home-manager.users.myusername = {
imports = [
m3ta-nixpkgs.homeManagerModules.default
];
m3ta.ports = {
enable = true;
definitions = {
dev-server = 3000;
};
currentHost = config.networking.hostName;
};
};
}
```
## Module Locations
- `modules/nixos/ports.nix` - Port management module
- `modules/nixos/mem0.nix` - Mem0 REST API server module
## Adding New Modules
1. Create module file: `modules/nixos/my-module.nix`
2. Follow standard pattern:
```nix
{ config, lib, pkgs, ... }:
with lib; let
cfg = config.m3ta.myModule;
in {
options.m3ta.myModule = {
enable = mkEnableOption "my module";
};
config = mkIf cfg.enable {
# Configuration
};
}
```
3. Import in `modules/nixos/default.nix`
## Related
- [Port Management Guide](../guides/port-management.md) - Detailed port management usage
- [Using Modules Guide](../guides/using-modules.md) - How to use modules
- [Home Manager Modules](./home-manager/overview.md) - User-level modules
+229
View File
@@ -0,0 +1,229 @@
# ports NixOS Module
Port management module for NixOS.
## Overview
This module provides centralized port management across multiple hosts. Define default ports and host-specific overrides to prevent conflicts.
See [Port Management Guide](../../guides/port-management.md) for detailed usage.
## Quick Start
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
# Define default ports
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
};
# Host-specific overrides
hostOverrides = {
laptop = {
nginx = 8080;
grafana = 3001;
};
};
# Current host
currentHost = config.networking.hostName;
};
}
```
## Module Options
### `m3ta.ports.enable`
Enable port management.
- Type: `boolean`
- Default: `false`
### `m3ta.ports.definitions`
Default port definitions.
- Type: `attrsOf int`
- Default: `{}`
Example:
```nix
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
};
```
### `m3ta.ports.hostOverrides`
Host-specific port overrides.
- Type: `attrsOf (attrsOf int)`
- Default: `{}`
Example:
```nix
hostOverrides = {
laptop = {
nginx = 8080;
grafana = 3001;
};
server = {
nginx = 80;
prometheus = 9091;
};
};
```
### `m3ta.ports.currentHost`
Current hostname. Determines which overrides to apply.
- Type: `string`
- Example: `config.networking.hostName`
## Functions
### `config.m3ta.ports.get "service"`
Get port for a service with host-specific override.
```nix
services.nginx = {
port = config.m3ta.ports.get "nginx";
};
```
If current host is `laptop` and `hostOverrides.laptop.nginx = 8080`, returns `8080`.
If no override, returns default `80`.
### `config.m3ta.ports.getHostPorts "hostname"`
Get all ports for a specific host.
```nix
# Get all ports for laptop
laptopPorts = config.m3ta.ports.getHostPorts "laptop";
# Returns: { nginx = 8080; grafana = 3000; ... }
```
### `config.m3ta.ports.listServices`
List all defined service names.
```nix
allServices = config.m3ta.ports.listServices;
# Returns: ["nginx" "grafana" "prometheus"]
```
## Usage Examples
### Basic Usage
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
};
currentHost = "server";
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
}
'';
};
}
```
### Multi-Host Setup
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
nginx = 80;
grafana = 3000;
prometheus = 9090;
};
hostOverrides = {
laptop = {
nginx = 8080;
grafana = 3001;
};
server = {
nginx = 80;
grafana = 3000;
};
};
currentHost = config.networking.hostName;
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
}
'';
};
}
```
### With Multiple Services
```nix
{config, ...}: {
m3ta.ports = {
enable = true;
definitions = {
# Monitoring
grafana = 3000;
prometheus = 9090;
loki = 3100;
promtail = 9080;
# Web
nginx = 80;
# Databases
postgres = 5432;
redis = 6379;
qdrant = 6333;
};
currentHost = config.networking.hostName;
};
# Use ports
services.grafana = {
enable = true;
settings.server.http_port = config.m3ta.ports.get "grafana";
};
services.postgresql = {
enable = true;
port = config.m3ta.ports.get "postgres";
};
}
```
## Related
- [Port Management Guide](../../guides/port-management.md) - Detailed guide
- [Home Manager Ports Module](../home-manager/ports.md) - User-level port management
+61
View File
@@ -0,0 +1,61 @@
# Packages
Documentation for packages in m3ta-nixpkgs. Each package directory may contain a `README.md` with detailed documentation.
## Index
Packages are organized in `pkgs/<name>/`. Add a `README.md` inside a package directory to document it here.
### Local Packages
These packages are built from source in `pkgs/<name>/`:
| Package | Description | Type | Location |
|---------|-------------|------|----------|
| `sidecar` | Companion tool for CLI agents with diffs, file trees, and task management | Go | `pkgs/sidecar/` |
| `td` | Minimalist CLI for tracking tasks across AI coding sessions | Go | `pkgs/td/` |
| `code2prompt` | Convert code to prompts | Go | `pkgs/code2prompt/` |
| `eigent` | Eigenvalue tool | Python | `pkgs/eigent/` |
| `hyprpaper-random` | Random wallpaper setter for Hyprpaper | Shell | `pkgs/hyprpaper-random/` |
| `kestractl` | CLI for Kestra workflow orchestration | Go | `pkgs/kestractl/` |
| `launch-webapp` | Launch web applications | Shell | `pkgs/launch-webapp/` |
| `mem0` | AI memory assistant with vector storage | Python | `pkgs/mem0/` |
| `msty-studio` | Msty Studio application | Python | `pkgs/msty-studio/` |
| `openshell` | AI shell assistant | Go | `pkgs/openshell/` |
| `openwork` | Open-source Claude Cowork alternative powered by opencode | AppImage | `pkgs/openwork/` |
| `pomodoro-timer` | Pomodoro timer utility | Shell | `pkgs/pomodoro-timer/` |
| `rofi-project-opener` | Rofi-based project launcher | Shell | `pkgs/rofi-project-opener/` |
| `stt-ptt` | Push to Talk Speech to Text | Python | `pkgs/stt-ptt/` |
| `tuxedo-backlight` | Backlight control for Tuxedo laptops | C | `pkgs/tuxedo-backlight/` |
| `vibetyper` | Typing practice tool | Python | `pkgs/vibetyper/` |
| `zellij-ps` | Project switcher for Zellij | Rust | `pkgs/zellij-ps/` |
### Overlay Modifications
These entries override upstream nixpkgs packages via `overlays.modifications`. They are also included in `overlays.default`.
| Package | Source | Modification | Location |
|---------|--------|--------------|----------|
| `n8n` | `nixpkgs#n8n` | Pins a newer release and fetch hashes | `overlays/mods/n8n.nix` |
### Pass-Through Packages
These packages are imported directly from flake inputs with minor modifications:
| Package | Source | Modification | Location |
|---------|--------|-------------|----------|
| `opencode-desktop` | `inputs.opencode` | Tauri desktop wrapper + Wayland fix | `pkgs/opencode-desktop/` |
## Adding Package Documentation
To document a package in detail, add a `README.md` inside the package directory (e.g., `pkgs/sidecar/README.md`). This guide indexes all packages and provides a quick overview.
## Automated Updates
Packages are automatically updated weekly by the Gitea Actions `nix-update` workflow. See the main README for details.
## Related
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Architecture](../ARCHITECTURE.md) - Repository structure
- [Quick Start](../QUICKSTART.md) - Getting started
+23
View File
@@ -0,0 +1,23 @@
# beads (Removed)
> **Note**: The `beads` package has been removed from this repository.
## Why was it removed?
The beads package was removed as it is no longer actively used.
## What was beads?
Beads was a lightweight memory system for AI coding agents with graph-based issue tracking. It provided:
- Persistent memory across AI sessions
- Graph-based issue tracking with dependencies
- Discovered work tracking
- Git integration
If you need beads, you can still build it from source:
```bash
git clone https://github.com/steveyegge/beads
cd beads
go build ./cmd/bd
```
+206
View File
@@ -0,0 +1,206 @@
# code2prompt
A CLI tool that converts your codebase into a single LLM prompt with a source tree, prompt templating, and token counting.
## Description
code2prompt is a command-line tool designed to help developers prepare their codebases for analysis by Large Language Models (LLMs). It creates a comprehensive prompt that includes:
- Source code tree structure
- Concatenated file contents
- Prompt templates
- Token counting for context management
## Features
- 📁 **Source Tree Generation**: Visual representation of your codebase structure
- 📝 **Code Concatenation**: Merges multiple files into a single prompt
- 🧩 **Prompt Templates**: Customizable prompt templates
- 🔢 **Token Counting**: Accurate token counting for various LLMs
- 🎯 **Selective Inclusion**: Choose specific files and directories
- 🔒 **Smart Filtering**: Exclude files by pattern (.git, node_modules, etc.)
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
code2prompt
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.code2prompt
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#code2prompt
```
## Usage
### Basic Usage
```bash
# Generate prompt for current directory
code2prompt
# Generate for specific directory
code2prompt /path/to/project
# Output to file
code2prompt -o prompt.txt
# Use custom template
code2prompt --template my_template.md
```
### Common Options
```bash
# Include specific files
code2prompt --include "*.py" "*.js"
# Exclude specific files
code2prompt --exclude "*.test.*" "node_modules/*"
# Generate source tree only
code2prompt --tree-only
# Add custom context
code2prompt --context "This is a Node.js project"
```
### Examples
#### Prepare Codebase for GPT-4
```bash
code2prompt \
--template gpt4-template.md \
--include "*.ts" "*.tsx" \
--exclude "node_modules" "*.test.ts" \
--context "Review this TypeScript codebase" \
-o codebase_prompt.txt
# Then feed to GPT-4
cat codebase_prompt.txt
```
#### Analyze Specific Directory
```bash
# Analyze only src directory
code2prompt src/ \
--include "*.rs" \
--context "Analyze this Rust codebase" \
-o src_analysis.txt
```
#### Create Source Tree
```bash
# Generate only source tree
code2prompt --tree-only > tree.txt
cat tree.txt
```
## Use Cases
### Code Review
Prepare code for AI-assisted code review:
```bash
code2prompt \
--template code-review.md \
--include "*.py" \
--context "Review this Python code for security issues" \
-o review_prompt.txt
```
### Documentation Generation
Generate documentation using LLMs:
```bash
code2prompt \
--template docs-template.md \
--include "*.js" "*.md" \
--context "Generate API documentation" \
-o docs_prompt.txt
```
### Code Migration
Prepare code for migration assistance:
```bash
code2prompt \
--template migration-template.md \
--include "*.js" \
--context "Migrate this JavaScript to TypeScript" \
-o migration_prompt.txt
```
## Configuration
### Environment Variables
- `CODE2PROMPT_TEMPLATE_DIR`: Directory containing custom templates
- `CODE2PROMPT_DEFAULT_TEMPLATE`: Default template to use
### Template Files
Custom templates can include:
```markdown
# Codebase Analysis
## Context
{context}
## Directory Tree
{tree}
## Code
{code}
## Instructions
{instructions}
```
## Build Information
- **Version**: 4.0.2
- **Language**: Rust
- **License**: MIT
- **Source**: [GitHub](https://github.com/mufeedvh/code2prompt)
## Dependencies
- `openssl` - Secure communication
- `pkg-config` - Build configuration
## Platform Support
- Linux (primary)
- macOS (may work)
- Windows (not tested)
## Related
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+190
View File
@@ -0,0 +1,190 @@
# hyprpaper-random
Minimal random wallpaper setter for Hyprpaper.
## Description
hyprpaper-random is a shell script that randomly selects and applies a wallpaper from a configured directory for use with Hyprpaper on Hyprland. It's designed to be minimal and fast.
## Features
- 🎲 **Random Selection**: Picks a random wallpaper from directory
- 🖼️ **Multi-Monitor Support**: Applies wallpaper to all monitors
- 📁 **Flexible Directory**: Configurable via environment variable
- 🔍 **Format Support**: jpg, jpeg, png, webp, avif
-**Fast**: Uses `fd` for quick file searching
- 🔄 **Safe**: Null-safe handling and error checking
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
hyprpaper-random
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.hyprpaper-random
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#hyprpaper-random
```
## Usage
### Basic Usage
```bash
# Use default directory ($XDG_CONFIG_HOME/hypr/wallpapers or ~/.config/hypr/wallpapers)
hyprpaper-random
# Use custom directory
WALLPAPER_DIR=~/Pictures/wallpapers hyprpaper-random
# Or set directory permanently
export WALLPAPER_DIR=~/Pictures/wallpapers
hyprpaper-random
```
### With Hyprpaper
Make sure Hyprpaper is running and loaded:
```bash
# Start Hyprpaper
hyprpaper &
# Set random wallpaper
hyprpaper-random
```
### Automate with Keybinding
Add to Hyprland config:
```nix
{pkgs, ...}: {
wayland.windowManager.hyprland.settings = {
bindm = [
"SUPER, mouse, movewindow"
];
bind = [
# Set random wallpaper on SUPER + W
"SUPER, W, exec, ${pkgs.hyprpaper-random}/bin/hyprpaper-random"
];
};
}
```
### Automate with Cron
```bash
# Change wallpaper every hour
0 * * * * hyprpaper-random
```
## Configuration
### Directory Setup
Default wallpaper directory:
```
$XDG_CONFIG_HOME/hypr/wallpapers/
# or
~/.config/hypr/wallpapers/
```
Custom directory:
```bash
# Temporary
WALLPAPER_DIR=~/Pictures/my-wallpapers hyprpaper-random
# Permanent (add to shell config)
export WALLPAPER_DIR=~/Pictures/my-wallpapers
```
### Environment Variables
- `WALLPAPER_DIR`: Path to wallpaper directory (default: `$XDG_CONFIG_HOME/hypr/wallpapers`)
- `XDG_CONFIG_HOME`: Config directory base (default: `~/.config`)
## Requirements
- `hyprland`: Hyprland window manager (for `hyprctl`)
- `hyprpaper`: Wallpaper utility for Hyprland
- `fd`: Fast file search
- `coreutils`: For `shuf` command
- `gawk`: Text processing
## Platform Support
- Linux (primary, requires Hyprland)
- macOS (not supported)
- Windows (not supported)
## Build Information
- **Version**: 0.1.1
- **Type**: Shell script
- **License**: MIT
## Troubleshooting
### No Wallpapers Found
Error: `No wallpapers found in: /path/to/dir`
**Solution**: Ensure wallpaper directory exists and contains images:
```bash
ls -la $WALLPAPER_DIR # Check directory exists
ls -la $WALLPAPER_DIR/*.jpg # Check for images
```
### Hyprctl Not Found
Error: `hyprctl: command not found`
**Solution**: Ensure Hyprland is installed:
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
hyprland
hyprpaper
];
}
```
### Wallpaper Not Changing
**Solution**: Check if Hyprpaper is running:
```bash
# Check status
hyprctl hyprpaper listloaded
# Check for errors
journalctl -u hyprpaper -f
```
## Related
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+115
View File
@@ -0,0 +1,115 @@
# kestractl
CLI for the Kestra workflow orchestration platform.
## Description
kestractl is the official command-line interface for [Kestra](https://kestra.io), an open-source workflow orchestration platform. It allows you to interact with Kestra instances to manage flows, trigger executions, inspect namespaces, and automate orchestration tasks from the terminal.
## Features
- 🔄 **Flow Management**: Deploy, inspect, and delete flows
- ▶️ **Execution Control**: Trigger and monitor workflow executions
- 📁 **Namespace Operations**: Manage Kestra namespaces and their resources
- 📂 **Namespace Files**: Upload and manage files in namespace storage
- 🌐 **Multi-Environment**: Switch between dev, staging, and production contexts
-**Pre-built Binary**: No compilation required — fetched directly from GitHub releases
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
kestractl
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.kestractl
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#kestractl
```
## Usage
### Basic Commands
```bash
# Check version
kestractl version
# Show help
kestractl --help
# Connect to a Kestra instance
kestractl context set --api-url http://localhost:8080
# List flows in a namespace
kestractl flow list --namespace my.namespace
# Trigger a flow execution
kestractl execution create --namespace my.namespace --flow-id my-flow
# Monitor executions
kestractl execution list --namespace my.namespace
```
## Configuration
kestractl uses a context system to manage connections to Kestra instances:
```bash
# Create a context for a local instance
kestractl context set local --api-url http://localhost:8080
# Create a context for a remote instance with auth
kestractl context set prod --api-url https://kestra.example.com --token <your-token>
# Switch active context
kestractl context use prod
```
## Build Information
- **Version**: 1.0.0
- **Language**: Go (pre-built binary)
- **License**: Apache 2.0
- **Source**: [GitHub](https://github.com/kestra-io/kestractl)
## Platform Support
- `x86_64-linux`
- `aarch64-linux`
## Package Structure
This package uses a `sources.json` + `update.sh` pattern for multi-platform binary fetching:
```
pkgs/kestractl/
├── default.nix — reads version + hashes from sources.json
├── sources.json — per-platform URLs and SRI hashes
└── update.sh — fetches latest GitHub release, updates sources.json
```
Updates are handled by `update.sh` (called by the Gitea Actions nix-update workflow), which fetches the latest release from GitHub, downloads each platform's tarball, computes SRI hashes, and rewrites `sources.json`.
## Related
- [Kestra Documentation](https://kestra.io/docs)
- [kestractl GitHub](https://github.com/kestra-io/kestractl)
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+180
View File
@@ -0,0 +1,180 @@
# launch-webapp
Launches a web app using your default browser in app mode.
## Description
launch-webapp is a shell script that launches web applications (like Discord, Spotify Web, etc.) in your default browser's "app mode". This provides a more native-like experience for web apps.
## Features
- 🌐 **Auto-Detection**: Detects your default web browser
- 🚀 **App Mode**: Launches in dedicated app window (no address bar)
- 🎨 **Native Feel**: Removes browser chrome for app-like experience
- 🔄 **Session Management**: Keeps web apps separate from regular browsing
- 🖥️ **Wayland Support**: Works with Wayland session managers (via `uwsm`)
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
launch-webapp
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.launch-webapp
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#launch-webapp
```
## Usage
### Basic Usage
```bash
# Launch web app
launch-webapp https://web.telegram.org
# Launch with additional arguments
launch-webapp https://web.whatsapp.com --app-name="WhatsApp"
```
### Examples
#### Launch Discord Web
```bash
launch-webapp https://discord.com/app
```
#### Launch Spotify Web
```bash
launch-webapp https://open.spotify.com
```
#### Launch Google Chat
```bash
launch-webapp https://chat.google.com
```
## Configuration
### Supported Browsers
The script auto-detects and supports:
- Google Chrome
- Brave Browser
- Microsoft Edge
- Opera
- Vivaldi
- Chromium (fallback)
### Default Browser
The script uses `xdg-settings` to detect your default browser.
```bash
# Check your default browser
xdg-settings get default-web-browser
```
### Wayland Support
The script uses `uwsm` (Wayland Session Manager) for proper Wayland support. Ensure `uwsm` is installed and configured.
## Desktop Integration
### Create Desktop Entry
Create `~/.local/share/applications/webapp-discord.desktop`:
```ini
[Desktop Entry]
Name=Discord Web
Comment=Discord Web App
Exec=launch-webapp https://discord.com/app
Icon=discord
Type=Application
Categories=Network;InstantMessaging;
```
### Add to Menu
The desktop entry will appear in your application menu after creating it.
## Requirements
- `xdg-utils`: For default browser detection
- `uwsm`: Wayland session manager
- Your preferred browser (Chrome, Brave, etc.)
## Platform Support
- Linux (primary, requires Wayland)
- macOS (not tested)
- Windows (not supported)
## Build Information
- **Version**: 0.1.0
- **Type**: Shell script
- **License**: MIT
## Troubleshooting
### Browser Not Found
If the script doesn't find your browser, ensure it's installed:
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
google-chrome
# or brave-browser, microsoft-edge, etc.
];
}
```
### Wayland Issues
If you encounter Wayland issues:
```bash
# Check uwsm is installed
which uwsm
# Check Wayland session
echo $XDG_SESSION_TYPE # Should be "wayland"
```
### App Won't Launch
Check the browser supports app mode:
```bash
# Test manually
google-chrome --app=https://example.com
```
## Related
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+268
View File
@@ -0,0 +1,268 @@
# mem0
Long-term memory layer for AI agents with REST API support.
## Description
Mem0 provides a sophisticated memory management system for AI applications and agents. It enables AI assistants to maintain persistent memory across conversations and sessions using vector storage.
## Features
- 💾 **Long-term Memory**: Persistent memory across conversations
- 🔍 **Semantic Search**: Vector-based similarity search
- 🤖 **Multiple LLM Support**: OpenAI, Anthropic, Groq, Ollama, etc.
- 📊 **Vector Stores**: Qdrant, Chroma, Pinecone, pgvector, etc.
- 🌐 **REST API**: Easy integration via HTTP endpoints
- 🎯 **Multi-modal Support**: Text and image memories
- 🔧 **Configurable**: Flexible LLM and embedding models
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
mem0
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.mem0
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#mem0
```
## Usage
### Command Line
```bash
# Start mem0 server
mem0-server
# With custom port
MEM0_PORT=8080 mem0-server
# With LLM provider
MEM0_LLM_PROVIDER=openai OPENAI_API_KEY=sk-xxx mem0-server
```
### Python Library
```python
from mem0 import Memory
# Initialize with OpenAI
memory = Memory(
llm_provider="openai",
llm_model="gpt-4o-mini",
vector_store="qdrant",
openai_api_key="sk-xxx"
)
# Add a memory
result = memory.add(
"I prefer coffee over tea",
metadata={"user_id": "123"}
)
# Search memories
memories = memory.search("What does the user prefer?")
```
### REST API
```bash
# Start server
mem0-server
# Add memory
curl -X POST http://localhost:8000/v1/memories \
-H "Content-Type: application/json" \
-d '{"content": "User likes Python"}'
# Search memories
curl http://localhost:8000/v1/memories/search?q=Python
```
## Configuration
### Environment Variables
```bash
# LLM Configuration
export MEM0_LLM_PROVIDER=openai
export MEM0_LLM_MODEL=gpt-4o-mini
export MEM0_LLM_TEMPERATURE=0.7
export OPENAI_API_KEY=sk-xxx
# Vector Store
export MEM0_VECTOR_PROVIDER=qdrant
export QDRANT_HOST=localhost
export QDRANT_PORT=6333
# Server
export MEM0_HOST=0.0.0.0
export MEM0_PORT=8000
export MEM0_WORKERS=4
export MEM0_LOG_LEVEL=info
```
### NixOS Module (Recommended)
Use the NixOS module for production:
```nix
{config, ...}: {
imports = [m3ta-nixpkgs.nixosModules.mem0];
m3ta.mem0 = {
enable = true;
port = 8000;
llm = {
provider = "openai";
apiKeyFile = "/run/secrets/openai-api-key";
model = "gpt-4o-mini";
};
vectorStore = {
provider = "qdrant";
config = {
host = "localhost";
port = 6333;
};
};
};
}
```
See [mem0 Module](../modules/nixos/mem0.md) for full module documentation.
## Supported LLM Providers
| Provider | Model Examples | Notes |
|----------|---------------|-------|
| `openai` | gpt-4, gpt-3.5-turbo | Most tested |
| `anthropic` | claude-3-opus, claude-3-sonnet | Requires key |
| `groq` | mixtral-8x7b-32768 | Fast inference |
| `ollama` | llama2, mistral | Local only |
| `together` | llama-2-70b | API access |
## Supported Vector Stores
| Provider | Requirements | Notes |
|----------|--------------|-------|
| `qdrant` | qdrant server | Recommended |
| `chroma` | chroma server | Simple setup |
| `pgvector` | PostgreSQL + pgvector | SQL-based |
| `pinecone` | Pinecone API | Cloud only |
| `redis` | Redis stack | Fast |
| `elasticsearch` | ES cluster | Scalable |
## Use Cases
### AI Chatbot with Memory
```python
from mem0 import Memory
memory = Memory()
# During conversation
memory.add("User works at Google as a software engineer")
# Later conversations
memories = memory.search("Where does the user work?")
# Returns: ["User works at Google as a software engineer"]
```
### Personal Assistant
```python
memory = Memory()
# Store preferences
memory.add("User prefers dark mode", metadata={"category": "preferences"})
memory.add("User is vegetarian", metadata={"category": "diet"})
# Retrieve relevant info
memories = memory.search("What should I cook for the user?")
```
### Code Assistant
```python
memory = Memory()
# Store project context
memory.add("This is a NixOS project with custom packages")
# Later analysis
memories = memory.search("What kind of project is this?")
```
## Requirements
### Vector Store
You need a vector store running. Example with Qdrant:
```nix
services.qdrant = {
enable = true;
port = 6333;
};
```
### LLM Provider
You need API keys or local models:
```nix
# OpenAI
services.mem0.llm.apiKeyFile = "/run/secrets/openai-api-key";
# Or use agenix
age.secrets.openai-api-key.file = ./secrets/openai.age;
```
## Build Information
- **Version**: 1.0.0
- **Language**: Python
- **License**: Apache-2.0
- **Source**: [GitHub](https://github.com/mem0ai/mem0)
## Python Dependencies
- `litellm` - Multi-LLM support
- `qdrant-client` - Qdrant client
- `pydantic` - Data validation
- `openai` - OpenAI client
- `fastapi` - REST API
- `uvicorn` - ASGI server
- `sqlalchemy` - Database ORM
## Platform Support
- Linux (primary)
- macOS (may work)
- Windows (not tested)
## Related
- [mem0 Module](../modules/nixos/mem0.md) - NixOS module documentation
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Port Management](../guides/port-management.md) - Managing service ports
- [Quick Start](../QUICKSTART.md) - Getting started guide
+172
View File
@@ -0,0 +1,172 @@
# msty-studio
Msty Studio enables advanced, privacypreserving AI workflows entirely on your local machine.
## Description
Msty Studio is a desktop application that provides a powerful AI development environment with a focus on privacy. All AI processing happens locally on your machine, ensuring your data never leaves your system.
## Features
- 🔒 **Privacy-First**: All AI processing happens locally
- 🤖 **Local AI Models**: Support for running local LLMs
- 📝 **Code Editor**: Integrated development environment
- 🔄 **Multiple Models**: Switch between different AI models
- 📊 **Model Management**: Download and manage local models
- 🎨 **Modern UI**: Clean, intuitive interface
-**Fast Performance**: Optimized for speed
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
msty-studio
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.msty-studio
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#msty-studio
```
## Usage
### Launch Application
```bash
# Launch Msty Studio
msty-studio
# Or from application menu
# Applications -> Msty Studio
```
### First Run
On first launch, you'll need to:
1. Download an AI model (if not already downloaded)
2. Configure model settings
3. Set up your workspace
### Managing Models
Through the Msty Studio interface, you can:
- Download new models
- Remove unused models
- Switch between models
- Configure model parameters
## Configuration
### Model Directory
Models are stored in your home directory:
```
~/.local/share/msty-studio/models/
```
### Settings
Msty Studio stores settings in:
```
~/.config/msty-studio/
```
### Integration with Nix
The package includes required dependencies:
- Node.js (for runtime)
- npm (for package management)
- uv (for Python packages)
- Python (for AI models)
## Requirements
### System Requirements
- Linux (x86_64)
- 8GB RAM minimum (16GB+ recommended)
- Modern CPU with AVX2 support
- GPU recommended (for faster inference)
### Dependencies
The package includes these dependencies:
- `nodejs` - JavaScript runtime
- `nodePackages.npm` - Package manager
- `uv` - Python package installer
- `python3` - Python runtime
## Platform Support
- Linux (x86_64 only)
- macOS (not supported)
- Windows (not supported)
**Note**: Msty Studio is distributed as an AppImage for Linux.
## Build Information
- **Version**: 2.0.0-beta.4
- **Type**: AppImage
- **License**: Proprietary (Unfree)
- **Source**: [msty.studio](https://msty.studio)
## Troubleshooting
### AppImage Won't Launch
Ensure executable bit is set:
```bash
chmod +x ~/.local/share/applications/msty-studio.desktop
```
### Models Not Downloading
Check disk space and network:
```bash
# Check disk space
df -h
# Check network
ping google.com
```
### Performance Issues
- Ensure you're using a GPU-accelerated model
- Close other resource-intensive applications
- Check system resources:
```bash
htop
nvidia-smi # If using NVIDIA GPU
```
## Related
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+302
View File
@@ -0,0 +1,302 @@
# n8n
Free and source-available fair-code licensed workflow automation tool. Easily automate tasks across different services.
## Description
n8n (pronounced "n-eight-n") is a workflow automation tool that helps you connect different services and automate tasks without writing code. It features a visual node-based editor for creating workflows with hundreds of integrations.
## Features
- 🎨 **Visual Workflow Editor**: Drag-and-drop interface for creating workflows
- 🔗 **Hundreds of Integrations**: Connect to popular services (Slack, GitHub, Google, etc.)
- 🔄 **Webhook Support**: Trigger workflows via HTTP requests
- 📝 **Code Node**: Execute JavaScript/TypeScript code within workflows
- 🚀 **Cloud & Self-Hosted**: Use n8n Cloud or self-host on your own infrastructure
- 📊 **Data Transformation**: Map and transform data between services
-**Scheduling**: Run workflows on schedules (cron-like)
- 🔒 **Security**: Credential management and secure data handling
- 🎯 **Fair-Code License**: Source available with usage restrictions for commercial use
## Installation
This repository does not publish a standalone `n8n` package. Instead, it provides an overlay that overrides the upstream nixpkgs `n8n` package with a newer pinned release when needed.
### Via Overlay
```nix
{inputs, pkgs, ...}: {
nixpkgs.overlays = [
inputs.m3ta-nixpkgs.overlays.default
# Or, if you only want package overrides:
# inputs.m3ta-nixpkgs.overlays.modifications
];
environment.systemPackages = with pkgs; [
n8n
];
}
```
## Usage
### Basic Usage
```bash
# Start n8n (default configuration)
n8n start
# Start with custom configuration file
n8n start --config /path/to/config
# Run in worker mode (for production with queue)
n8n worker
# Execute a workflow from file
n8n execute /path/to/workflow.json
```
### Development Mode
```bash
# Start with tunnel (external access)
n8n start --tunnel
# Disable telemetry
n8n start --no-telemetry
# Specify workflow directory
n8n start --workflows /path/to/workflows
# Enable/disable features
n8n start --enable-editor
n8n start --disable-metrics
```
### Workflow Management
```bash
# Export workflow to file
n8n export:workflow --id=123 --output=workflow.json
# Import workflow from file
n8n import:workflow --input=workflow.json
# Execute workflow
n8n execute:workflow --id=123
```
## Configuration
### Environment Variables
- `N8N_BASIC_AUTH_ACTIVE`: Enable basic authentication (default: false)
- `N8N_BASIC_AUTH_USER`: Basic auth username
- `N8N_BASIC_AUTH_PASSWORD`: Basic auth password
- `N8N_ENCRYPTION_KEY`: Encryption key for credentials
- `N8N_HOST`: Host URL for web UI (default: localhost)
- `N8N_PORT`: Port for web UI (default: 5678)
- `N8N_PROTOCOL`: Protocol (http or https)
- `N8N_PATH`: Path to mount n8n (default: /)
- `N8N_EDITOR_BASE_URL`: Base URL for editor
- `N8N_WEBHOOK_URL`: URL for webhook endpoints
- `N8N_TIMEZONE`: Timezone for execution (default: UTC)
- `N8N_LOG_LEVEL`: Logging level (output, warn, error, verbose)
- `N8N_LOG_OUTPUT`: Log output destination (console, file)
- `N8N_METRICS`: Enable metrics collection (default: true)
- `DB_TYPE`: Database type (sqlite3db, postgresdb, mysqldb)
- `DB_SQLITE_VACUUM_ON_STARTUP`: Vacuum SQLite on startup
### Database Configuration
By default, n8n uses SQLite for simplicity. For production, use PostgreSQL or MySQL:
```bash
# PostgreSQL
export DB_TYPE=postgresdb
export DB_POSTGRESDB_HOST=localhost
export DB_POSTGRESDB_PORT=5432
export DB_POSTGRESDB_DATABASE=n8n
export DB_POSTGRESDB_USER=n8n
export DB_POSTGRESDB_PASSWORD=yourpassword
# MySQL/MariaDB
export DB_TYPE=mysqldb
export DB_MYSQLDB_HOST=localhost
export DB_MYSQLDB_PORT=3306
export DB_MYSQLDB_DATABASE=n8n
export DB_MYSQLDB_USER=n8n
export DB_MYSQLDB_PASSWORD=yourpassword
```
### Security
Set up encryption for credentials:
```bash
# Generate encryption key
export N8N_ENCRYPTION_KEY=$(openssl rand -base64 32)
# Use in production
export N8N_ENCRYPTION_KEY="your-32-char-encryption-key"
```
## NixOS Module
For NixOS, use the n8n module from nixpkgs for a complete service configuration:
```nix
services.n8n = {
enable = true;
settings = {
host = "0.0.0.0";
port = 5678;
timezone = "UTC";
};
environment = {
N8N_ENCRYPTION_KEY = "your-encryption-key";
DB_TYPE = "postgresdb";
DB_POSTGRESDB_HOST = "/var/run/postgresql";
DB_POSTGRESDB_DATABASE = "n8n";
};
};
```
## Use Cases
### Webhook Automation
Trigger workflows via HTTP requests:
```bash
# Start n8n with tunnel for public URL
n8n start --tunnel
# Create webhook workflow in UI
# Workflow receives data from external service
# Process and send to another service
```
### Scheduled Tasks
Run tasks on a schedule:
```javascript
// In workflow editor, use Schedule Trigger
// Set cron expression: "0 9 * * *" (daily at 9 AM)
// Connect to nodes that perform tasks
```
### Data Sync Between Services
Keep data synchronized:
```bash
# Create workflow with:
# 1. Webhook trigger (service A)
# 2. Data transformation node
# 3. HTTP request node (service B)
# 4. Response back to service A
```
### Automated Reporting
Generate and send reports:
```javascript
// Workflow steps:
// 1. Schedule trigger (daily/weekly)
// 2. Database query node
// 3. Data formatting
// 4. Email or Slack notification
```
## Integration Examples
### Slack Integration
```javascript
// Create Slack notification workflow
// 1. Trigger (webhook or schedule)
// 2. Process data
// 3. Send message to Slack channel
```
### GitHub Integration
```javascript
// GitHub repository automation
// 1. GitHub webhook trigger (push, PR, issue)
// 2. Conditional logic
// 3. Actions (create issue, comment, etc.)
```
### Email Automation
```javascript
// Email processing workflow
// 1. Email trigger (IMAP)
// 2. Parse email content
// 3. Process data
// 4. Send response or forward
```
## Performance Optimization
### Production Tips
- Use PostgreSQL or MySQL instead of SQLite
- Enable queue mode with Redis
- Use worker nodes for scaling
- Configure proper resource limits
- Set up load balancing for web UI
### Queue Mode
```bash
# Start main n8n process
export QUEUE_BULL_REDIS_HOST=redis-server
export QUEUE_BULL_REDIS_PORT=6379
n8n start
# Start worker processes
n8n worker
```
## Build Information
- **Version**: 2.29.8
- **Language**: TypeScript/JavaScript (Node.js)
- **Package Manager**: pnpm
- **License**: Sustainable Use (Fair-Code)
- **Source**: [GitHub](https://github.com/n8n-io/n8n)
## Dependencies
- `nodejs` - JavaScript runtime
- `pnpm` - Package manager (build-time)
- `python3` - Required for SQLite bindings
- `node-gyp` - Node.js native addon build tool
- `libkrb5` - Kerberos authentication
- `libmongocrypt` - MongoDB encryption
- `libpq` - PostgreSQL client library
## Platform Support
- Linux
- macOS
## Notes
- Package has ~80,000 files, so stripping and ELF patching are disabled for performance
- SQLite3 bindings are rebuilt during build phase
- TypeScript files and source maps are removed in preInstall phase
- Non-deterministic files (.turbo, .modules.yaml, types) are removed
- Node modules are pruned to production dependencies only
## Related
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
- [n8n Documentation](https://docs.n8n.io) - Official documentation
- [n8n Community](https://community.n8n.io) - Community forum
+37
View File
@@ -0,0 +1,37 @@
# opencode (Deprecated)
> **Note**: The `opencode` package has been removed from this repository.
## Why was it removed?
OpenCode (CLI version) has been removed because there is now a well-maintained upstream repository for AI coding tools:
**[numtide/llm-agents.nix](https://github.com/numtide/llm-agents.nix)**
This repository provides Nix packages for various AI coding agents, including OpenCode and others, with active maintenance and updates.
## What should I use instead?
Use the [llm-agents.nix](https://github.com/numtide/llm-agents.nix) flake directly:
```nix
{
inputs = {
llm-agents.url = "github:numtide/llm-agents.nix";
};
outputs = { inputs, ... }: {
# Access packages via inputs.llm-agents.packages.${system}
};
}
```
Or run directly:
```bash
nix run github:numtide/llm-agents.nix#opencode
```
## What about opencode-desktop?
The `opencode-desktop` package remains available in this repository as it includes a Wayland support workaround for [upstream issue #11755](https://github.com/opencode-ai/opencode/issues/11755). Once this issue is resolved upstream, `opencode-desktop` may also be removed in favor of the llm-agents.nix repository.
+220
View File
@@ -0,0 +1,220 @@
# pomodoro-timer
A work timer based on the Pomodoro Technique.
## Description
A simple, shell-based Pomodoro timer that uses `timer`, Kitty terminal, Rofi, libnotify, and speech synthesis to provide visual and audio feedback for work and break sessions.
## Features
- ⏱️ **Pomodoro Technique**: 45-minute work, 10-minute break cycles
- 🎨 **Terminal UI**: Floating Kitty terminal window
- 📋 **Rofi Menu**: Easy session selection
- 🔔 **Notifications**: Desktop and voice notifications
- ⚙️ **Custom Times**: Set custom durations
- 🎯 **Quick Access**: Simple keybinding integration
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
launch-timer # The main program is named launch-timer
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.launch-timer
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#launch-timer
```
## Usage
### Basic Usage
```bash
# Launch timer selection menu
launch-timer
```
This opens a Rofi menu with three options:
1. **work** - 45-minute work session
2. **break** - 10-minute break session
3. **custom** - Custom time duration
### Session Options
#### Work Session
```bash
# Select "work" from menu
# Starts 45-minute timer
```
#### Break Session
```bash
# Select "break" from menu
# Starts 10-minute timer
```
#### Custom Time
```bash
# Select "custom" from menu
# Enter time in format: 25m, 1h, 30s
# Examples:
# 25m - 25 minutes
# 1h - 1 hour
# 30s - 30 seconds
```
### Time Formats
Supported formats:
| Format | Example | Description |
|---------|----------|-------------|
| `Xm` | `25m` | X minutes |
| `Xh` | `1h` | X hours |
| `Xs` | `30s` | X seconds |
## Configuration
### Keybinding Integration
Add to Hyprland config:
```nix
{pkgs, ...}: {
wayland.windowManager.hyprland.settings = {
bind = [
# Launch Pomodoro timer with SUPER + T
"SUPER, T, exec, ${pkgs.launch-timer}/bin/launch-timer"
];
};
}
```
### Custom Defaults
Modify the script for custom defaults:
```bash
# Change work duration
start_timer "60m" "work"
# Change break duration
start_timer "15m" "break"
```
## Requirements
### Dependencies
- `timer` - Terminal timer utility
- `kitty` - Terminal emulator
- `rofi` - Application launcher
- `libnotify` - Desktop notifications
- `speechd` - Text-to-speech synthesis
### System Requirements
- Linux (primary)
- Desktop environment with notification support
- Audio output for speech synthesis
## Platform Support
- Linux (primary)
- macOS (not supported)
- Windows (not supported)
## Behavior
### Timer Window
- Opens as floating Kitty window
- Window class: `floating-pomodoro`
- Window title: `floating-pomodoro`
### Notifications
When session ends, you'll receive:
1. Desktop notification: "work session ended!" or "break session ended!"
2. Voice announcement: "work session ended" or "break session ended"
### Input Validation
For custom times:
- Valid: `25m`, `1h`, `30s`, `1h30m`
- Invalid: `25`, `abc`, `1.5h`
## Build Information
- **Version**: 0.1.0
- **Type**: Shell script
- **License**: MIT
- **Main Program**: `launch-timer`
## Troubleshooting
### Kitty Not Found
Ensure Kitty is installed:
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
kitty
];
}
```
### No Notifications
Ensure notification daemon is running:
```bash
# Check for notification daemon
ps aux | grep -i notify
# Start notification daemon
# Depends on your DE: dunst, mako, etc.
```
### Speech Not Working
Check if speech synthesis is working:
```bash
# Test speech
spd-say "Hello"
# Check if speech-dispatcher is running
ps aux | grep speech-dispatcher
```
## Related
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+245
View File
@@ -0,0 +1,245 @@
# rofi-project-opener
A Rofi-based project directory launcher for quickly opening projects in your terminal with custom commands.
## Description
rofi-project-opener scans configured base directories for project subdirectories and presents them in a Rofi menu. When a project is selected, it opens a terminal, navigates to the project directory, and runs a configurable command (defaults to `opencode`).
Key features:
- JSON-based configuration for project directories
- Per-directory custom arguments (e.g., `--agent chiron` for AI coding assistants)
- Placeholder support (`%s` for path, `%a` for args) in custom commands
- Works with any terminal emulator
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
rofi-project-opener
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.rofi-project-opener
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#rofi-project-opener
```
## Usage
### Basic Usage
```bash
# Launch rofi project selector
rofi-project-opener
```
This will:
1. Read project directories from `~/.config/rofi-project-opener/projects.json`
2. Scan each directory for subdirectories (non-hidden)
3. Display projects in Rofi for fuzzy selection
4. Open terminal, cd to project, and run the configured command
### Configuration Files
The script uses two configuration files in `~/.config/rofi-project-opener/`:
**projects.json** - Project directories with optional args:
```json
{
"nixpkgs": {"path": "~/p/NIX", "args": ""},
"chat": {"path": "~/p/CHAT", "args": "--agent chiron"},
"dev": {"path": "~/dev", "args": ""}
}
```
**config** - Terminal and Rofi settings:
```bash
TERMINAL="/path/to/kitty"
TERMINAL_CMD="opencode %a"
ROFI_PROMPT="Select project"
ROFI_ARGS="-dmenu -i"
```
### Placeholders
When using `terminalCommand`, these placeholders are available:
| Placeholder | Description |
|-------------|-------------|
| `%s` | Full path to selected project |
| `%a` | Args from projectDirs config |
**Examples:**
```nix
terminalCommand = "opencode %a"; # opencode with project args
terminalCommand = "nvim"; # just nvim, no args
terminalCommand = "code %s"; # vscode with explicit path
terminalCommand = "myapp --dir %s %a"; # custom app with both
```
## Home Manager Module
### Enable Module
```nix
{config, pkgs, ...}: {
imports = [m3ta-nixpkgs.homeManagerModules.default];
cli.rofi-project-opener = {
enable = true;
projectDirs = {
nixpkgs = { path = "~/p/NIX"; };
chat = { path = "~/p/CHAT"; args = "--agent chiron"; };
dev = { path = "~/dev"; };
};
terminal = pkgs.kitty;
terminalCommand = "opencode %a";
};
}
```
### Module Options
#### `cli.rofi-project-opener.enable`
Enable the rofi-project-opener module.
- Type: `boolean`
- Default: `false`
#### `cli.rofi-project-opener.projectDirs`
Attribute set of base directories to scan for projects.
- Type: `attrsOf (submodule { path, args })`
- Default: `{ dev = { path = "~/dev"; }; projects = { path = "~/projects"; }; }`
Each entry supports:
- `path` (required): Base directory path
- `args` (optional): Arguments to pass to the command
#### `cli.rofi-project-opener.terminal`
Terminal emulator to use.
- Type: `either str package`
- Default: `"kitty"`
#### `cli.rofi-project-opener.terminalCommand`
Command to run in the terminal. Supports `%s` (path) and `%a` (args) placeholders.
- Type: `str`
- Default: `""` (runs `opencode %a`)
#### `cli.rofi-project-opener.rofiPrompt`
Prompt text displayed in Rofi.
- Type: `str`
- Default: `"Select project"`
#### `cli.rofi-project-opener.rofiArgs`
Arguments to pass to Rofi.
- Type: `listOf str`
- Default: `["-dmenu" "-i"]`
## Requirements
### System Requirements
- Linux with Rofi installed
- A terminal emulator (kitty, alacritty, etc.)
- jq (included as dependency)
### Runtime Dependencies
These are automatically included:
- rofi
- jq
- coreutils
- gnugrep
- gnused
- libnotify
## Platform Support
- Linux (primary)
- macOS (not tested)
- Windows (not supported)
## Build Information
- **Type**: Bash script
- **License**: MIT
## Troubleshooting
### No Projects Found
Check that your project directories exist and contain subdirectories:
```bash
cat ~/.config/rofi-project-opener/projects.json
ls ~/p/NIX # Should show subdirectories
```
### Args Not Being Passed
Make sure you're using `%a` placeholder in your `terminalCommand`:
```nix
# Wrong - args not passed
terminalCommand = "opencode";
# Correct - args passed via placeholder
terminalCommand = "opencode %a";
# Also correct - empty uses default behavior with args
terminalCommand = "";
```
### Rofi Not Showing
Ensure Rofi is installed and working:
```bash
echo -e "item1\nitem2" | rofi -dmenu
```
### Terminal Not Opening
Check terminal configuration:
```nix
# Using package
terminal = pkgs.kitty;
# Using string (must be in PATH)
terminal = "kitty";
```
## Related
- [rofi-project-opener Module](../modules/home-manager/cli/rofi-project-opener.md) - Home Manager module documentation
- [zellij-ps](./zellij-ps.md) - Similar project switcher for Zellij
- [Using Modules](../guides/using-modules.md) - How to use modules
+134
View File
@@ -0,0 +1,134 @@
# sidecar
A companion tool for CLI coding agents, providing diffs, file trees, conversation history, and task management with td integration.
## Description
sidecar is a terminal UI tool designed to enhance the experience of using AI coding agents in the terminal. It provides a side panel interface for viewing diffs, file trees, conversation history, and integrates with `td` for task management across coding sessions.
## Features
- 🔀 **Diff Viewer**: Visual diff display for code changes
- 📁 **File Tree**: Navigate and understand project structure
- 💬 **Conversation History**: Review and search past AI interactions
-**Task Management**: Integrated with `td` for tracking tasks
- 🖥️ **Terminal UI**: Clean interface using tmux panes
- 🤖 **AI Agent Integration**: Designed to work with opencode and similar CLI agents
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
sidecar
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.sidecar
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#sidecar
```
## Usage
### Starting sidecar
```bash
# Start sidecar alongside your AI coding agent
sidecar
# Start with a specific agent
sidecar --agent opencode
```
### Basic Commands
```bash
# Show help
sidecar --help
# Check version
sidecar --version
```
## Dependencies
sidecar is packaged with the following runtime dependencies:
- **opencode**: AI coding agent
- **td**: Task tracking CLI
- **tmux**: Terminal multiplexer for UI layout
These are automatically included in the PATH when running sidecar.
## Workflow Integration
### Typical Session
1. Start `sidecar` in your project directory
2. The tool opens a tmux session with panes for:
- Your AI coding agent (opencode)
- Task list (via td)
- Diff viewer
- File tree navigator
3. Work with your AI agent as usual
4. View diffs and changes in real-time
5. Track tasks using the integrated td panel
### With opencode
```bash
# sidecar automatically integrates with opencode
cd your-project
sidecar
```
## Configuration
### Environment Variables
- `SIDECAR_CONFIG`: Custom configuration file path
- `SIDECAR_AGENT`: Default AI agent to use (default: opencode)
### Customization
Configuration is managed through sidecar's own config system. See the upstream documentation for details.
## Build Information
- **Version**: 0.71.1
- **Language**: Go
- **License**: MIT
- **Source**: [GitHub](https://github.com/marcus/sidecar)
## Platform Support
- Linux
- macOS (Unix systems)
## Notes
- Tests are disabled in the Nix package build
- The package wraps the binary with required dependencies (opencode, td, tmux) in PATH
- Version check is enabled for the Nix package
## Related
- [td](./td.md) - Task tracking CLI used by sidecar
- [opencode](./opencode.md) - AI coding agent integration
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+202
View File
@@ -0,0 +1,202 @@
# stt-ptt
Push to Talk Speech to Text using Whisper.
## Description
stt-ptt is a simple push-to-talk speech-to-text tool that uses whisper.cpp for transcription. It records audio via PipeWire, transcribes it using a local Whisper model, and types the result using wtype (Wayland).
## Features
- **Push to Talk**: Start/stop recording with simple commands
- **Local Processing**: Uses whisper.cpp for fast, offline transcription
- **Wayland Native**: Types transcribed text using wtype
- **Configurable**: Model path and notification timeout via environment variables
- **Lightweight**: Minimal dependencies, no cloud services
## Installation
### Via Home Manager Module (Recommended)
See [stt-ptt Home Manager Module](../modules/home-manager/cli/stt-ptt.md) for the recommended setup with automatic model download.
### Via Overlay
```nix
{pkgs, ...}: {
home.packages = [pkgs.stt-ptt];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
home.packages = [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.stt-ptt
];
}
```
## Usage
### Basic Commands
```bash
# Start recording
stt-ptt start
# Stop recording and transcribe
stt-ptt stop
```
### Keybinding Setup
The tool is designed to be bound to a key (e.g., hold to record, release to transcribe).
#### Hyprland
```nix
# In your Hyprland config
wayland.windowManager.hyprland.settings = {
bind = [
# Press Super+V to start, release to stop and transcribe
"SUPER, V, exec, stt-ptt start"
];
bindr = [
# Release trigger
"SUPER, V, exec, stt-ptt stop"
];
};
```
Or in `hyprland.conf`:
```conf
bind = SUPER, V, exec, stt-ptt start
bindr = SUPER, V, exec, stt-ptt stop
```
#### Sway
```conf
# Hold to record, release to transcribe
bindsym --no-repeat $mod+v exec stt-ptt start
bindsym --release $mod+v exec stt-ptt stop
```
#### i3 (X11 - requires xdotool instead of wtype)
Note: stt-ptt uses wtype which is Wayland-only. For X11, you would need to modify the script to use xdotool.
### Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `STT_MODEL` | Path to Whisper model file | `~/.local/share/stt-ptt/models/ggml-large-v3-turbo.bin` |
| `STT_NOTIFY_TIMEOUT` | Notification timeout in ms | `3000` |
## Requirements
- **whisper-cpp**: Speech recognition engine
- **wtype**: Wayland text input (Wayland compositor required)
- **libnotify**: Desktop notifications
- **pipewire**: Audio recording
## Model Setup
Download a Whisper model from [HuggingFace](https://huggingface.co/ggerganov/whisper.cpp/tree/main):
```bash
# Create model directory
mkdir -p ~/.local/share/stt-ptt/models
# Download model (example: large-v3-turbo)
curl -L -o ~/.local/share/stt-ptt/models/ggml-large-v3-turbo.bin \
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin
```
Or use the Home Manager module which handles this automatically.
## Available Models
| Model | Size | Quality | Speed |
|-------|------|---------|-------|
| `ggml-tiny` / `ggml-tiny.en` | 75MB | Basic | Fastest |
| `ggml-base` / `ggml-base.en` | 142MB | Good | Fast |
| `ggml-small` / `ggml-small.en` | 466MB | Better | Medium |
| `ggml-medium` / `ggml-medium.en` | 1.5GB | High | Slower |
| `ggml-large-v3-turbo` | 1.6GB | High | Fast |
| `ggml-large-v3` | 2.9GB | Highest | Slowest |
Models ending in `.en` are English-only and slightly faster for English text.
## Platform Support
- Linux with Wayland (primary)
- Requires PipeWire for audio
- X11 not supported (wtype is Wayland-only)
## Build Information
- **Version**: 0.1.0
- **Type**: Shell script wrapper
- **License**: MIT
## Troubleshooting
### Model Not Found
Error: `Error: Model not found at /path/to/model`
**Solution**: Download a model or use the Home Manager module:
```bash
curl -L -o ~/.local/share/stt-ptt/models/ggml-large-v3-turbo.bin \
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin
```
### No Audio Recorded
**Solution**: Ensure PipeWire is running:
```bash
systemctl --user status pipewire
```
### Text Not Typed
**Solution**: Ensure you're on Wayland and wtype has access:
```bash
# Check if running on Wayland
echo $XDG_SESSION_TYPE # Should print "wayland"
```
### Slow Transcription
**Solution**: Use a smaller model or enable GPU acceleration:
```nix
cli.stt-ptt = {
enable = true;
model = "ggml-base.en"; # Smaller, faster model
};
```
Or with GPU acceleration:
```nix
cli.stt-ptt = {
enable = true;
# Choose one:
whisperPackage = pkgs.whisper-cpp-vulkan; # Vulkan (pre-built)
# whisperPackage = pkgs.whisper-cpp.override { cudaSupport = true; }; # NVIDIA
# whisperPackage = pkgs.whisper-cpp.override { rocmSupport = true; }; # AMD
};
```
## Related
- [stt-ptt Home Manager Module](../modules/home-manager/cli/stt-ptt.md) - Module documentation
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
+130
View File
@@ -0,0 +1,130 @@
# td
Minimalist CLI for tracking tasks across AI coding sessions.
## Description
td (task daemon) is a lightweight command-line tool designed for tracking tasks during AI-assisted coding sessions. It provides a simple, fast way to manage todos and maintain context across conversations with AI coding agents.
## Features
-**Minimal Task Tracking**: Simple, focused task management
- 🤖 **AI Session Aware**: Designed to work with AI coding workflows
- 📊 **Usage Tracking**: Track session usage and context
- 🔄 **Session Continuity**: Resume tasks from previous sessions
- 📝 **Git Integration**: Works alongside git workflows
-**Fast**: Lightweight Go binary with minimal overhead
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
td
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.td
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#td
```
## Usage
### Starting a Session
```bash
# Start a new session and view current tasks
td usage --new-session
# Quick view of current tasks (no session tracking)
td usage -q
```
### Basic Commands
```bash
# Show version
td version
# View help
td --help
```
### Task Management
td integrates with AI coding workflows to track tasks across sessions. Use it at the start of conversations to establish context:
```bash
# At conversation start (or after /clear)
td usage --new-session
# For subsequent reads within the same session
td usage -q
```
## Integration with AI Agents
td is designed to be used by AI coding agents as part of their workflow:
1. **Session Start**: Agent reads current tasks with `td usage --new-session`
2. **Work Progress**: Tasks are tracked and updated during the session
3. **Session End**: State is preserved for the next session
### Example Integration
In an AI agent's system prompt or configuration:
```
You must run td usage --new-session at conversation start (or after /clear) to see current work.
Use td usage -q for subsequent reads.
```
## Configuration
### Environment Variables
- `TD_DATA_DIR`: Custom directory for td data storage
### Data Storage
Task data is stored locally in the project or user directory. See upstream documentation for exact storage location.
## Build Information
- **Version**: 0.34.0
- **Language**: Go
- **License**: MIT
- **Source**: [GitHub](https://github.com/marcus/td)
## Platform Support
- Linux
- macOS (Unix systems)
## Notes
- Tests are disabled in the Nix package build due to git worktree operations
- Version check is enabled for the Nix package (`td version`)
- Minimal dependencies - pure Go binary
## Related
- [sidecar](./sidecar.md) - Uses td for integrated task management
- [opencode](./opencode.md) - AI coding agent that integrates with td
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+248
View File
@@ -0,0 +1,248 @@
# tuxedo-backlight
Keyboard backlight control for Tuxedo laptops.
## Description
A shell script that sets up RGB keyboard backlight colors for Tuxedo laptops with customizable colors for different key groups.
## Features
- ⌨️ **RGB Backlight**: Full RGB keyboard backlight support
- 🎨 **Color Groups**: Different colors for different key groups
- 🔤 **Key Highlighting**: Special colors for modifier keys
- 🎯 **One-Command Setup**: Apply all colors with single command
- ⚡ **Fast**: Direct sysfs control
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
tuxedo-backlight
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.tuxedo-backlight
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#tuxedo-backlight
```
## Usage
### Basic Usage
```bash
# Apply default color scheme
tuxedo-backlight
```
### Colors
The script applies these colors by default:
| Key Group | Color (RGB) | Description |
|-----------|-------------|-------------|
| Main keys | `0 150 255` | Blue (Cyan-ish) |
| Function keys (F1-F12) | `0 255 80` | Green (Lime) |
| Arrow keys | `0 255 80` | Green (Lime) |
| Numpad area | `255 150 0` | Orange |
| DEL key | `255 0 155` | Pink/Magenta |
| ESC key | `255 0 155` | Pink/Magenta |
## Customization
### Modify Colors
Edit the script to customize colors:
```nix
# In pkgs/tuxedo-backlight/default.nix
# All keys
echo 'R G B' | tee /sys/class/leds/rgb:kbd_backlight*/multi_intensity
# Specific key (e.g., ESC)
echo 'R G B' | tee /sys/class/leds/rgb:kbd_backlight/multi_intensity
```
RGB format: `Red Green Blue` (0-255 each)
### Color Examples
| Color | RGB Value |
|--------|-----------|
| Red | `255 0 0` |
| Green | `0 255 0` |
| Blue | `0 0 255` |
| Cyan | `0 255 255` |
| Magenta | `255 0 255` |
| Yellow | `255 255 0` |
| White | `255 255 255` |
| Orange | `255 150 0` |
| Purple | `150 0 255` |
## Automatic Startup
### Systemd Service
Create `/etc/systemd/system/tuxedo-backlight.service`:
```ini
[Unit]
Description=Tuxedo Keyboard Backlight
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/run/current-system/sw/bin/tuxedo-backlight
[Install]
WantedBy=multi-user.target
```
Enable and start:
```bash
sudo systemctl enable tuxedo-backlight.service
sudo systemctl start tuxedo-backlight.service
```
### NixOS Configuration
```nix
{pkgs, ...}: {
# Run at boot
systemd.services.tuxedo-backlight = {
description = "Set Tuxedo keyboard backlight";
after = ["multi-user.target"];
wantedBy = ["multi-user.target"];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.tuxedo-backlight}/bin/tuxedo-backlight";
};
};
}
```
## Requirements
### Hardware
- Tuxedo laptop with RGB keyboard backlight
- Linux kernel with appropriate driver support
### System Requirements
- Linux (Tuxedo laptops)
- Write access to `/sys/class/leds/`
### Permissions
The script requires write access to sysfs:
```bash
# Check permissions
ls -la /sys/class/leds/rgb:kbd_backlight*
# If permissions are needed
sudo tuxedo-backlight
```
## Platform Support
- Linux (Tuxedo laptops only)
- macOS (not supported)
- Windows (not supported)
## Troubleshooting
### No Such Device
Error: `No such file or directory`
**Solution**: Ensure you're on a Tuxedo laptop with RGB keyboard:
```bash
# Check if RGB backlight exists
ls -la /sys/class/leds/rgb:kbd_backlight*
```
### Permission Denied
Error: `Permission denied`
**Solution**: Run with sudo or configure udev rules:
```bash
# Run with sudo
sudo tuxedo-backlight
# Or create udev rule for user access
sudo vim /etc/udev/rules.d/99-tuxedo-backlight.rules
```
udev rule:
```
SUBSYSTEM=="leds", ATTR{brightness}=="*", ACTION=="add", RUN+="/usr/bin/chgrp -R input /sys/class/leds/rgb:*"
SUBSYSTEM=="leds", ATTR{brightness}=="*", ACTION=="add", RUN+="/usr/bin/chmod -R g+w /sys/class/leds/rgb:*"
```
### Colors Not Applied
**Solution**:
1. Check RGB backlight is supported:
```bash
cat /sys/class/leds/rgb:kbd_backlight*/multi_intensity
```
2. Ensure driver is loaded:
```bash
# Check for Tuxedo drivers
lsmod | grep tuxedo
# Load if needed
sudo modprobe tuxedo_keyboard
```
## Key Layout Reference
The script sets colors for these key groups:
### Key Numbers
- **All keys**: Main keyboard area (except special keys)
- **15**: DEL key
- **No number**: ESC key
- **1-12, 102**: Function keys (F1-F12, Fn)
- **16-19, 36-39, 56-59, 76-79, 96-99, 117-119**: Numpad and keys above numpad
- **95, 114-116**: Arrow keys
## Build Information
- **Version**: 0.1.0
- **Type**: Shell script
- **License**: MIT
## Related
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+204
View File
@@ -0,0 +1,204 @@
# zellij-ps
A Zellij project switcher for quickly navigating and opening project workspaces.
## Description
zellij-ps is a Fish script inspired by ThePrimeagen's tmux-sessionizer. It provides a fast, interactive way to switch between project folders in Zellij. Using `fd` for fast directory discovery and `fzf` for fuzzy selection, it helps you quickly jump into your work.
The script searches through your configured project folders (`$PROJECT_FOLDERS`) and either creates a new Zellij session for the selected project or attaches to an existing one.
## Installation
### Via Overlay
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
zellij-ps
];
}
```
### Direct Reference
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
inputs.m3ta-nixpkgs.packages.${pkgs.system}.zellij-ps
];
}
```
### Run Directly
```bash
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#zellij-ps
```
## Usage
### Basic Usage
```bash
# Run from outside Zellij to start a project session
zellij-ps
# Or pass a project path directly
zellij-ps ~/projects/my-project
```
This will:
1. Search through your `$PROJECT_FOLDERS` for directories
2. Open fzf for fuzzy project selection (if no argument provided)
3. Create a new Zellij session or attach to existing one for the selected project
### Configuration
Set your project folders in your shell configuration:
**Fish example:**
```fish
set -x PROJECT_FOLDERS ~/projects:~/code:~/work
```
**Bash/Zsh example:**
```bash
export PROJECT_FOLDERS="$HOME/projects:$HOME/code:$HOME/work"
```
Folders should be delimited by `:` and can include `~` for home directory.
## Home Manager Module
### Enable Module
```nix
{config, ...}: {
imports = [m3ta-nixpkgs.homeManagerModules.default];
cli.zellij-ps = {
enable = true;
};
}
```
### Module Options
#### `cli.zellij-ps.enable`
Enable the zellij-ps module.
- Type: `boolean`
- Default: `false`
#### `cli.zellij-ps.package`
Custom package to use.
- Type: `package`
- Default: `pkgs.zellij-ps`
## Requirements
### System Requirements
- Linux or Unix-like system
- Configured `$PROJECT_FOLDERS` environment variable
## Platform Support
- Linux (primary)
- macOS (may work)
- Windows (not supported)
## Build Information
- **Version**: 0.1.0
- **Type**: Fish script
- **License**: MIT
- **Inspired by**: [ThePrimeagen's tmux-sessionizer](https://github.com/ThePrimeagen/.dotfiles/blob/master/bin/.local/scripts/tmux-sessionizer)
- **Source**: [Gitea](https://code.m3ta.dev/m3tam3re/helper-scripts)
## Source Code
The script is available at:
```
https://code.m3ta.dev/m3tam3re/helper-scripts/src/branch/main/zellij-ps.fish
```
## Troubleshooting
### No Projects Found
If fzf shows no results, check your `$PROJECT_FOLDERS` variable:
```bash
# In fish
echo $PROJECT_FOLDERS
# In bash/zsh
echo $PROJECT_FOLDERS
```
Ensure the folders exist and contain subdirectories.
### Already in Zellij Session
If you're already inside a Zellij session, you'll see:
```
You are in a Zellij Session!
Please use the session manager to switch sessions.
```
Use Zellij's built-in session manager (`Ctrl+p``s`) to switch sessions instead.
### fd Not Found
Error: `fd: command not found`
**Solution**: Ensure fd is installed:
```nix
{pkgs, ...}: {
environment.systemPackages = with pkgs; [
fd
];
}
```
### Fish Not Found
Error: `fish: command not found`
**Solution**: Ensure Fish is installed:
```nix
{pkgs, ...}: {
programs.fish = {
enable = true;
};
}
```
### fzf Not Working
Ensure fzf is installed and configured:
```bash
# Check fzf
which fzf
# Test fzf
echo -e "item1\nitem2\nitem3" | fzf
```
## Related
- [zellij-ps Module](../modules/home-manager/cli/zellij-ps.md) - Home Manager module documentation
- [Using Modules](../guides/using-modules.md) - How to use modules
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
- [Quick Start](../QUICKSTART.md) - Getting started guide
+245
View File
@@ -0,0 +1,245 @@
# Library Functions
Documentation for library functions available in m3ta-nixpkgs.
## Overview
The library provides helper functions for your NixOS and Home Manager configurations.
## Available Libraries
### `m3ta-lib.ports`
Port management utilities for managing service ports across hosts.
## Port Management Functions
### `mkPortHelpers`
Create port helper functions from a ports configuration.
#### Signature
```nix
mkPortHelpers :: portsConfig -> portHelpers
```
#### Arguments
`portsConfig` - An attribute set with structure:
```nix
{
ports = { service-name = port-number; ... };
hostPorts = { hostname = { service-name = port-number; ... }; ... };
}
```
#### Returns
An attribute set containing helper functions:
```nix
{
getPort = service: host -> port-number-or-null;
getHostPorts = host -> ports-attrs;
listServices = -> [string];
}
```
#### Usage
```nix
{config, inputs, ...}: let
m3taLib = inputs.m3ta-nixpkgs.lib.${config.system};
myPorts = {
ports = {
nginx = 80;
grafana = 3000;
};
hostPorts = {
laptop = {
nginx = 8080;
};
};
};
portHelpers = m3taLib.ports.mkPortHelpers myPorts;
in {
# Get port with host override
services.nginx.port = portHelpers.getPort "nginx" config.networking.hostName;
# Get all ports for host
laptopPorts = portHelpers.getHostPorts "laptop";
# List all services
allServices = portHelpers.listServices;
}
```
### `getPort` (from portHelpers)
Get port for a service, with optional host-specific override.
#### Signature
```nix
getPort :: string -> string -> int-or-null
```
#### Arguments
1. `service` - The service name (string)
2. `host` - The hostname (string), or `null` for default
#### Returns
Port number (int) or `null` if service not found.
#### Usage
```nix
services.nginx = {
port = portHelpers.getPort "nginx" "laptop"; # Returns host-specific port
# or
port = portHelpers.getPort "nginx" null; # Returns default port
};
```
### `getHostPorts` (from portHelpers)
Get all ports for a specific host (merges defaults with host overrides).
#### Signature
```nix
getHostPorts :: string -> attrs
```
#### Arguments
1. `host` - The hostname (string)
#### Returns
Attribute set of all ports for the host.
#### Usage
```nix
laptopPorts = portHelpers.getHostPorts "laptop";
# Returns: { nginx = 8080; grafana = 3000; prometheus = 9090; ... }
```
### `listServices` (from portHelpers)
List all defined service names.
#### Signature
```nix
listServices :: -> [string]
```
#### Returns
List of service names (strings).
#### Usage
```nix
allServices = portHelpers.listServices;
# Returns: ["nginx" "grafana" "prometheus" "homepage"]
```
## Using Library Functions
### Importing
```nix
{config, inputs, ...}: let
# Import library
m3taLib = inputs.m3ta-nixpkgs.lib.${config.system};
in {
# Use library functions
}
```
### Example: Custom Port Management
```nix
{config, inputs, ...}: let
m3taLib = inputs.m3ta-nixpkgs.lib.${config.system};
myPorts = {
ports = {
web = 80;
api = 8080;
db = 5432;
};
hostPorts = {
dev = {
web = 8080;
api = 8081;
};
};
};
portHelpers = m3taLib.ports.mkPortHelpers myPorts;
hostname = config.networking.hostName;
in {
services.nginx = {
enable = true;
virtualHosts.${hostname} = {
locations."/" = {
proxyPass = "http://localhost:${toString (portHelpers.getPort "api" hostname)}";
};
};
};
services.postgresql = {
enable = true;
port = portHelpers.getPort "db" hostname;
};
}
```
### Example: Generate Config Files
```nix
{inputs, ...}: let
m3taLib = inputs.m3ta-nixpkgs.lib.${system};
myPorts = {
ports = {
service1 = 3000;
service2 = 3001;
};
};
portHelpers = m3taLib.ports.mkPortHelpers myPorts;
in {
environment.etc."ports.toml".text = generators.toTOML {} {
services = portHelpers.getHostPorts "desktop";
};
}
```
## Function Reference Summary
| Function | Purpose | Return Type |
|----------|---------|------------|
| `mkPortHelpers` | Create port helper functions | `portHelpers` attrs |
| `getPort` | Get port with optional host override | `int or null` |
| `getHostPorts` | Get all ports for host | `attrs` |
| `listServices` | List all service names | `[string]` |
## Related
- [Port Management Guide](../guides/port-management.md) - Detailed usage guide
- [NixOS Ports Module](../modules/nixos/ports.md) - Port management module
- [Home Manager Ports Module](../modules/home-manager/ports.md) - User-level port management
- [Architecture](../ARCHITECTURE.md) - Understanding library functions
+498
View File
@@ -0,0 +1,498 @@
# Code Patterns and Anti-Patterns
Common code patterns and anti-patterns used in m3ta-nixpkgs.
## Overview
This document outlines recommended patterns and common pitfalls when working with m3ta-nixpkgs.
## Code Patterns
### Package Pattern
#### CallPackage Registry
Use `callPackage` for lazy evaluation:
```nix
# Good - pkgs/default.nix
{
inherit (pkgs) callPackage;
} rec {
code2prompt = callPackage ./code2prompt {};
mem0 = callPackage ./mem0 {};
}
```
#### Meta Fields
Always include complete `meta` information:
```nix
# Good
meta = with lib; {
description = "My awesome package";
homepage = "https://github.com/author/package";
changelog = "https://github.com/author/package/releases/tag/v${version}";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "program-name";
};
```
### Module Pattern
#### Standard Module Structure
```nix
# Good
{ config, lib, pkgs, ... }:
with lib; let
cfg = config.m3ta.myModule;
in {
options.m3ta.myModule = {
enable = mkEnableOption "my module";
# ... options
};
config = mkIf cfg.enable {
# ... configuration
};
}
```
#### mkEnableOption
Always use `mkEnableOption` for enable flags:
```nix
# Good
options.m3ta.myModule = {
enable = mkEnableOption "my module";
};
# Bad
options.m3ta.myModule.enable = mkOption {
type = types.bool;
default = false;
};
```
#### Conditional Configuration
Use `mkIf` for conditional config:
```nix
# Good
config = mkIf cfg.enable {
services.my-service.enable = true;
};
```
#### Multiple Conditions
Use `mkMerge` for multiple conditions:
```nix
# Good
config = mkMerge [
(mkIf cfg.feature1.enable {
# config for feature1
})
(mkIf cfg.feature2.enable {
# config for feature2
})
];
```
### Import Pattern
#### Multi-line Imports
Multi-line, trailing commas:
```nix
# Good
{
lib,
stdenv,
fetchFromGitHub,
}:
```
#### Explicit Dependencies
```nix
# Good
{
lib,
stdenv,
openssl,
pkg-config,
}:
stdenv.mkDerivation {
buildInputs = [openssl pkg-config];
}
```
## Anti-Patterns
### lib.fakeHash in Commits
**Bad**: Committing `lib.fakeHash`
```nix
# Bad - Never commit this!
src = fetchFromGitHub {
hash = lib.fakeHash;
};
```
**Solution**: Build to get real hash:
```bash
nix build .#your-package
# Copy actual hash from error message
```
### Flat Module Files
**Bad**: All modules in one file
```nix
# Bad - Hard to maintain
{config, lib, pkgs, ...}: {
options.m3ta.cli = {
tool1 = mkEnableOption "tool1";
tool2 = mkEnableOption "tool2";
# ... many more
};
config = mkMerge [
(mkIf config.cli.tool1.enable {...})
(mkIf config.cli.tool2.enable {...})
# ... many more
];
}
```
**Solution**: Organize by category
```nix
# Good - modules/home-manager/cli/
# modules/home-manager/cli/default.nix
{
imports = [
./tool1.nix
./tool2.nix
];
}
```
### Hardcoded Ports
**Bad**: Hardcoding ports in services
```nix
# Bad
services.nginx = {
enable = true;
httpConfig = ''
server {
listen 80;
}
'';
};
```
**Solution**: Use port management
```nix
# Good
m3ta.ports = {
enable = true;
definitions = {nginx = 80;};
};
services.nginx = {
enable = true;
httpConfig = ''
server {
listen ${toString (config.m3ta.ports.get "nginx")};
}
'';
};
```
### Skipping Meta Fields
**Bad**: Incomplete meta information
```nix
# Bad
meta = {
description = "My package";
};
```
**Solution**: Include all fields
```nix
# Good
meta = with lib; {
description = "My awesome package";
homepage = "https://github.com/author/package";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "program-name";
};
```
### with pkgs; in Modules
**Bad**: Using `with pkgs;` at module level
```nix
# Bad
{config, lib, pkgs, ...}: with pkgs; {
config.environment.systemPackages = [
vim
git
];
}
```
**Solution**: Explicit package references or limited with
```nix
# Good - Explicit references
{config, lib, pkgs, ...}: {
config.environment.systemPackages = with pkgs; [
vim
git
];
}
# Or - Full references
{config, lib, pkgs, ...}: {
config.environment.systemPackages = [
pkgs.vim
pkgs.git
];
}
```
### Orphaned Package Directories
**Bad**: Creating directory without registering
```nix
# Bad - Package not visible
# pkgs/my-package/default.nix exists
# But pkgs/default.nix doesn't reference it
```
**Solution**: Register in `pkgs/default.nix`
```nix
# Good
{
inherit (pkgs) callPackage;
} rec {
my-package = callPackage ./my-package {};
}
```
## Type Safety
### No Type Suppression
**Bad**: Using `as any`
```nix
# Bad
let
value = someFunction config as any;
in
# ...
```
**Solution**: Fix underlying type issues
```nix
# Good
let
value = someFunction config;
in
# Ensure value has correct type
```
### Proper Type Definitions
```nix
# Good
options.m3ta.myModule = {
enable = mkEnableOption "my module";
port = mkOption {
type = types.port;
default = 8080;
description = "Port to run on";
};
};
```
## Naming Conventions
### Package Names
**Good**: `lowercase-hyphen`
```nix
code2prompt
hyprpaper-random
launch-webapp
```
**Bad**: CamelCase or underscores
```nix
code2Prompt # Bad
hyprpaper_random # Bad
```
### Variables
**Good**: `camelCase`
```nix
portHelpers
configFile
serviceName
```
**Bad**: Snake_case or kebab-case
```nix
port_helpers # Bad
port-helpers # Bad
```
### Module Options
**Good**: `m3ta.*` namespace for m3ta modules, `cli.*` namespace for CLI modules
```nix
m3ta.ports.enable = true;
cli.zellij-ps.enable = true;
```
**Bad**: Flat namespace
```nix
ports.enable = true; # Potential conflict
zellij-ps.enable = true; # Hard to find
```
## Performance
### Lazy Evaluation
**Good**: Use `callPackage`
```nix
# Good - Only builds requested package
code2prompt = callPackage ./code2prompt {};
```
**Bad**: Building all packages
```nix
# Bad - Builds everything even if not used
code2prompt = import ./code2prompt {};
```
### Selective Imports
**Good**: Import only needed modules
```nix
# Good
imports = [
m3ta-nixpkgs.nixosModules.mem0
];
```
**Bad**: Importing all modules
```nix
# Bad - Imports and evaluates all modules
imports = [
m3ta-nixpkgs.nixosModules.default
];
```
## Security
### No Secrets in Store
**Bad**: Putting secrets in configuration
```nix
# Bad - Secret in Nix store
m3ta.mem0.llm.apiKey = "sk-xxx";
```
**Solution**: Use secret files
```nix
# Good - Secret from file
m3ta.mem0.llm.apiKeyFile = "/run/secrets/openai-api-key";
```
### Proper User/Group
**Good**: Dedicated users for services
```nix
# Good
users.users.mem0 = {
isSystemUser = true;
group = "mem0";
};
```
### Service Hardening
**Good**: Enable systemd hardening
```nix
# Good
systemd.services.mem0.serviceConfig = {
NoNewPrivileges = true;
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
};
```
## Best Practices Summary
| Practice | Do | Don't |
|----------|-----|--------|
| Hash fetching | Get real hash from build error | Commit `lib.fakeHash` |
| Module organization | Categorize by function | Put all in one file |
| Port management | Use `m3ta.ports` module | Hardcode ports |
| Meta fields | Include all fields | Skip fields |
| Type safety | Fix type errors | Use `as any` |
| Dependencies | Explicit declarations | Implicit deps |
| Imports | Multi-line, trailing comma | Single-line, no comma |
| Naming | Follow conventions | Mix styles |
| Secrets | Use file-based | Put in config |
| Evaluation | Lazy (`callPackage`) | Import everything |
## Related
- [Contributing Guide](../CONTRIBUTING.md) - Code style and guidelines
- [Architecture](../ARCHITECTURE.md) - Understanding repository structure
- [Adding Packages](../guides/adding-packages.md) - Package creation patterns
+162
View File
@@ -0,0 +1,162 @@
# Templates
Boilerplate templates for quickly adding new packages or modules to m3ta-nixpkgs.
## Available Templates
| Template | Command | Creates |
|---------|---------|---------|
| Package | `nix flake init -t .#package` | `templates/package/` |
| NixOS Module | `nix flake init -t .#nixos-module` | `templates/nixos-module/` |
| Home Manager Module | `nix flake init -t .#home-manager-module` | `templates/home-manager-module/` |
## Using Templates
### 1. List Available Templates
```bash
nix flake show --templates .
```
### 2. Initialize from a Template
```bash
# Package
nix flake init -t .#package
# NixOS Module
nix flake init -t .#nixos-module
# Home Manager Module
nix flake init -t .#home-manager-module
```
Note: `nix flake init` copies the template contents into the current directory. Use a subdirectory name:
```bash
mkdir new-package && cd new-package
nix flake init -t ..#package
```
## Package Template
Creates a complete package structure:
```
templates/package/
├── default.nix # Package definition with comments
```
### Fields to Fill In
| Field | Location | Notes |
|-------|----------|-------|
| `pname` | `default.nix` | Package name (kebab-case) |
| `version` | `default.nix` | Semantic version |
| `src` | `default.nix` | Fetcher (GitHub, URL, Git, etc.) |
| `hash` | `default.nix` | Use `lib.fakeHash`, build to get real hash |
| `meta.description` | `default.nix` | Short one-line description |
| `meta.homepage` | `default.nix` | Project URL |
| `meta.license` | `default.nix` | Use `lib.licenses.*` |
| `meta.platforms` | `default.nix` | Usually `platforms.linux` |
| `meta.mainProgram` | `default.nix` | Main binary name |
### Common Build Systems
```nix
# Rust (recommended)
rustPlatform.buildRustPackage rec { ... }
# Python
python3.pkgs.buildPythonPackage rec { ... }
# Node.js
pkg-config, nodejs, npm2nix, or pnpm + prisma
# Shell script
writeShellScriptBin "name" ''echo hello''
# Go
go mdbook build
# Generic C/Make
stdenv.mkDerivation { ... }
```
See [Adding Packages](./guides/adding-packages.md) for detailed instructions.
## NixOS Module Template
Creates a complete NixOS module:
```
templates/nixos-module/
├── default.nix # Module with options
└── README.md # Module documentation
```
### Fields to Fill In
| Field | Location | Notes |
|-------|----------|-------|
| Module name | `default.nix` | File name matches `m3ta.<name>` |
| Options | `default.nix` | Add under `options.m3ta.<name>` |
| Config | `default.nix` | Add under `config.m3ta.<name>` |
| Description | `README.md` | What the module does |
### After Creating
1. Add to `modules/nixos/default.nix` imports
2. Optionally export from `flake.nix` `nixosModules`
3. Add documentation to `docs/modules/nixos/`
4. Run `nix flake check`
## Home Manager Module Template
Creates a complete Home Manager module:
```
templates/home-manager-module/
├── default.nix # Module with options
└── README.md # Module documentation
```
### Fields to Fill In
| Field | Location | Notes |
|-------|----------|-------|
| Category | Directory | Choose `cli/` or `coding/` |
| Options | `default.nix` | Add under `options.m3ta.<name>` |
| Config | `default.nix` | Add under `config.m3ta.<name>` |
| Description | `README.md` | What the module does |
### After Creating
1. Add to the appropriate category aggregator (`cli/default.nix` or `coding/default.nix`)
2. Optionally export from `flake.nix` `homeManagerModules`
3. Add documentation to `docs/modules/home-manager/`
4. Run `nix flake check`
## Template Variables
Templates use Nix attribute references. After copying, search for these placeholders:
| Placeholder | Replace With |
|-------------|--------------|
| `package-name` | Your package name (kebab-case) |
| `owner-name` / `repo-name` | GitHub owner and repo |
| `0.1.0` | Initial version |
| `lib.fakeHash` | Real hash after first build |
| `lib.licenses.mit` | Appropriate license |
| `A short description` | One-line description |
## Automated Updates
Packages created from templates are automatically updated weekly by the Gitea Actions workflow. See the main README for details on the `nix-update` automation.
## Related
- [Adding Packages](./guides/adding-packages.md) - Detailed package guide
- [Adding Modules](./guides/adding-modules.md) - Detailed module guide
- [Development Workflow](./guides/development-workflow.md) - Local development
- [Architecture](./ARCHITECTURE.md) - Repository structure
+193
View File
@@ -0,0 +1,193 @@
# Example Standalone Home Manager Configuration using m3ta-nixpkgs
# This file demonstrates how to use m3ta-nixpkgs with standalone Home Manager
# (without NixOS)
{
description = "Example Home Manager configuration with m3ta-nixpkgs";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
# Add m3ta-nixpkgs as an input
m3ta-nixpkgs = {
url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
# Or use a local path during development:
# url = "path:/home/user/projects/m3ta-nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
home-manager,
m3ta-nixpkgs,
...
} @ inputs: let
system = "x86_64-linux"; # Change to your system: aarch64-linux, x86_64-darwin, aarch64-darwin
pkgs = import nixpkgs {
inherit system;
config.allowUnfree = true;
# Apply m3ta-nixpkgs overlays
overlays = [
m3ta-nixpkgs.overlays.default
];
};
in {
homeConfigurations = {
# Replace 'm3tam3re' with your actual username
m3tam3re = home-manager.lib.homeManagerConfiguration {
inherit pkgs;
# Pass inputs as extra special args
extraSpecialArgs = {inherit inputs;};
modules = [
# Import m3ta's Home Manager modules
m3ta-nixpkgs.homeManagerModules.default
# Main Home Manager configuration
{
# ============================================
# User Information
# ============================================
home.username = "m3tam3re";
home.homeDirectory = "/home/m3tam3re";
home.stateVersion = "24.05";
# ============================================
# Packages from m3ta-nixpkgs
# ============================================
# Since we applied the overlay above, packages are available directly
home.packages = with pkgs; [
# Custom packages from m3ta-nixpkgs
code2prompt
hyprpaper-random
launch-webapp
msty-studio
pomodoro-timer
zellij-ps
# Regular packages from nixpkgs
git
vim
htop
fzf
ripgrep
];
# ============================================
# Custom Home Manager Modules
# ============================================
# If you've defined custom Home Manager modules
# programs.myProgram = {
# enable = true;
# package = pkgs.myProgram;
# settings = {
# theme = "dark";
# };
# };
# ============================================
# Shell Configuration
# ============================================
programs.bash = {
enable = true;
shellAliases = {
ll = "ls -l";
".." = "cd ..";
};
};
programs.zsh = {
enable = true;
enableCompletion = true;
autosuggestion.enable = true;
syntaxHighlighting.enable = true;
};
# ============================================
# Git Configuration
# ============================================
programs.git = {
enable = true;
userName = "Your Name";
userEmail = "your.email@example.com";
extraConfig = {
init.defaultBranch = "main";
pull.rebase = false;
};
};
# ============================================
# Additional Programs
# ============================================
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};
programs.fzf = {
enable = true;
enableBashIntegration = true;
enableZshIntegration = true;
};
# ============================================
# Environment Variables
# ============================================
home.sessionVariables = {
EDITOR = "vim";
VISUAL = "vim";
};
# ============================================
# File Management
# ============================================
# Create custom config files
home.file.".config/my-app/config.json".text = ''
{
"setting": "value"
}
'';
# ============================================
# Allow Home Manager to manage itself
# ============================================
programs.home-manager.enable = true;
}
];
};
# ============================================
# Minimal Example Configuration
# ============================================
minimal = home-manager.lib.homeManagerConfiguration {
pkgs = import nixpkgs {
inherit system;
overlays = [m3ta-nixpkgs.overlays.default];
};
modules = [
{
home.username = "m3tam3re";
home.homeDirectory = "/home/m3tam3re";
home.stateVersion = "24.05";
# Just use a couple of custom packages
home.packages = with pkgs; [
code2prompt
zellij-ps
];
programs.home-manager.enable = true;
}
];
};
};
};
}
+153
View File
@@ -0,0 +1,153 @@
# Example NixOS Configuration using m3ta-nixpkgs
# This file demonstrates how to integrate m3ta-nixpkgs into your NixOS system
{
description = "Example NixOS configuration with m3ta-nixpkgs";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
# Add m3ta-nixpkgs as an input
m3ta-nixpkgs = {
url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
# Or use a local path during development:
# url = "path:/home/user/projects/m3ta-nixpkgs";
inputs.nixpkgs.follows = "nixpkgs";
};
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
self,
nixpkgs,
m3ta-nixpkgs,
home-manager,
...
} @ inputs: {
nixosConfigurations = {
# Replace 'hostname' with your actual hostname
hostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = {inherit inputs;};
modules = [
# Your hardware configuration
./hardware-configuration.nix
# Import m3ta's NixOS modules (if any are defined)
m3ta-nixpkgs.nixosModules.default
# Main configuration
({pkgs, ...}: {
# ============================================
# METHOD 1: Using Overlays (Recommended)
# ============================================
# This makes custom packages available as if they were in nixpkgs
nixpkgs.overlays = [
m3ta-nixpkgs.overlays.default
# Or use individual overlays for more control:
# m3ta-nixpkgs.overlays.additions
# m3ta-nixpkgs.overlays.modifications
];
# Now you can use packages normally
environment.systemPackages = with pkgs; [
# Custom packages from m3ta-nixpkgs
code2prompt
hyprpaper-random
msty-studio
pomodoro-timer
tuxedo-backlight
zellij-ps
# Regular nixpkgs packages
vim
git
htop
];
# ============================================
# METHOD 2: Direct Package Reference
# ============================================
# Use this if you don't want to use overlays
# environment.systemPackages = [
# inputs.m3ta-nixpkgs.packages.${pkgs.system}.code2prompt
# inputs.m3ta-nixpkgs.packages.${pkgs.system}.zellij-ps
# ];
# ============================================
# Using Custom NixOS Modules
# ============================================
# If you've defined custom NixOS modules, configure them here
# m3ta.myModule = {
# enable = true;
# # module-specific options
# };
# ============================================
# System Configuration
# ============================================
system.stateVersion = "24.05";
networking.hostName = "hostname";
# Enable flakes
nix.settings.experimental-features = ["nix-command" "flakes"];
})
# ============================================
# Home Manager Integration
# ============================================
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.m3tam3re = {pkgs, ...}: {
# Import m3ta's Home Manager modules
imports = [
m3ta-nixpkgs.homeManagerModules.default
# Or import specific modules:
# m3ta-nixpkgs.homeManagerModules.zellij-ps
];
# Home Manager packages with overlay
home.packages = with pkgs; [
launch-webapp
# Other packages...
];
# Configure custom Home Manager modules
# programs.myProgram = {
# enable = true;
# # options...
# };
home.stateVersion = "24.05";
};
}
];
};
# ============================================
# Alternative: Minimal Configuration
# ============================================
minimal = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
({pkgs, ...}: {
nixpkgs.overlays = [m3ta-nixpkgs.overlays.default];
environment.systemPackages = with pkgs; [
code2prompt
];
system.stateVersion = "24.05";
})
];
};
};
};
}
Generated
+104
View File
@@ -0,0 +1,104 @@
{
"nodes": {
"agents": {
"flake": false,
"locked": {
"lastModified": 1780133320,
"narHash": "sha256-8AiN9tV9PBb5xblJiPlhumBbKj61qLjzqXXFtkj3vvY=",
"ref": "refs/heads/master",
"rev": "920c00313ae242bd93275c30131b9ab1e52ee2fb",
"revCount": 88,
"type": "git",
"url": "https://code.m3ta.dev/m3tam3re/AGENTS"
},
"original": {
"type": "git",
"url": "https://code.m3ta.dev/m3tam3re/AGENTS"
}
},
"basecamp": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1774505501,
"narHash": "sha256-7UiRrDptj7yuEFwToOfdunUMz/i3jRLR7CmMoYQjq6k=",
"owner": "basecamp",
"repo": "basecamp-cli",
"rev": "f087e6ef84002503d0dbc75ea1c8c928a8928d9e",
"type": "github"
},
"original": {
"owner": "basecamp",
"ref": "v0.7.2",
"repo": "basecamp-cli",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1782467914,
"narHash": "sha256-pGvFkM8N0xEkIIXDe5YYfbEAvHrk4IxBrjB/x8OomhE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e73de5be04e0eff4190a1432b946d469c794e7b4",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-master": {
"locked": {
"lastModified": 1782540244,
"narHash": "sha256-3skOZJEfAUG7LSB/Ok2AQUiqeagYLSq+8wKjtS1hOyc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a65184fc373636356fcaf460dc09655a919c66ea",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "master",
"repo": "nixpkgs",
"type": "github"
}
},
"openspec": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1782291243,
"narHash": "sha256-0pVn5pDqlKpqSgzf4eG9TFCjkjzOtnmGTpbILso7GwI=",
"owner": "Fission-AI",
"repo": "OpenSpec",
"rev": "737518b36fe4b6fdb09c83eeaf8d873a428c92e6",
"type": "github"
},
"original": {
"owner": "Fission-AI",
"repo": "OpenSpec",
"type": "github"
}
},
"root": {
"inputs": {
"agents": "agents",
"basecamp": "basecamp",
"nixpkgs": "nixpkgs",
"nixpkgs-master": "nixpkgs-master",
"openspec": "openspec"
}
}
},
"root": "root",
"version": 7
}
+128
View File
@@ -0,0 +1,128 @@
{
description = "m3ta's personal Nix repository - Custom packages, overlays, and modules";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-master.url = "github:NixOS/nixpkgs/master";
basecamp = {
url = "github:basecamp/basecamp-cli/v0.7.2";
inputs.nixpkgs.follows = "nixpkgs";
};
# openspec - spec-driven development for AI coding assistants
openspec = {
url = "github:Fission-AI/OpenSpec";
inputs.nixpkgs.follows = "nixpkgs";
};
# Agent definitions and coding rules
agents = {
url = "git+https://code.m3ta.dev/m3tam3re/AGENTS";
flake = false;
};
};
outputs = {
self,
nixpkgs,
...
} @ inputs: let
# Supported systems
systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"];
# Helper function to generate an attrset for each of the systems
forAllSystems = nixpkgs.lib.genAttrs systems;
# Helper to create pkgs for a given system
pkgsFor = system:
import nixpkgs {
inherit system;
config.allowUnfree = true;
};
in {
# Custom packages - accessible via 'nix build .#package-name'
packages = forAllSystems (system: let
pkgs = pkgsFor system;
in
import ./pkgs {inherit pkgs inputs;});
# Overlays - can be imported in your system configuration
overlays = import ./overlays {inherit inputs;};
# NixOS modules - for system-level configuration
nixosModules = {
default = ./modules/nixos;
# Individual modules for selective imports
ports = ./modules/nixos/ports.nix;
mem0 = ./modules/nixos/mem0.nix;
};
# Home Manager modules - for user-level configuration
homeManagerModules = {
default = import ./modules/home-manager;
ports = import ./modules/home-manager/ports.nix;
opencode = import ./modules/home-manager/coding/opencode.nix;
agents = import ./modules/home-manager/coding/agents;
zellij-ps = import ./modules/home-manager/zellij-ps.nix;
};
# Library functions - helper utilities for your configuration
lib = forAllSystems (system: import ./lib {lib = nixpkgs.lib;});
# Development shells for various programming environments
# Usage: nix develop .#<shell-name>
# Available shells: default, python, devops, coding
devShells = forAllSystems (system: let
pkgs = pkgsFor system;
in
import ./shells {
inherit pkgs inputs;
agents = inputs.agents;
});
# Formatter for 'nix fmt'
formatter = forAllSystems (system: (pkgsFor system).alejandra);
# Checks for 'nix flake check' - verifies all packages build
checks = forAllSystems (system: let
pkgs = pkgsFor system;
packages = import ./pkgs {inherit pkgs inputs;};
in
builtins.mapAttrs (name: pkg: pkgs.lib.hydraJob pkg) packages
// {
formatting = pkgs.runCommand "check-formatting" {} ''
${pkgs.alejandra}/bin/alejandra --check ${./.}
touch $out
'';
n8n-overlay = import ./tests/n8n-overlay-test.nix {
inherit pkgs inputs self;
};
# Lib unit tests
lib-agents = import ./tests/lib/agents-test.nix {
inherit pkgs;
lib = pkgs.lib;
};
lib-coding-rules = import ./tests/lib/coding-rules-test.nix {
inherit pkgs;
lib = pkgs.lib;
};
});
# Templates for creating new packages/modules
templates = {
package = {
path = ./templates/package;
description = "Template for a new package";
};
nixos-module = {
path = ./templates/nixos-module;
description = "Template for a new NixOS module";
};
home-manager-module = {
path = ./templates/home-manager-module;
description = "Template for a new Home Manager module";
};
};
};
}
+433
View File
@@ -0,0 +1,433 @@
# Harness-agnostic agent management utilities
#
# This module provides functions to load canonical agent definitions and
# render them for different AI coding tools (OpenCode, Claude Code, Pi).
#
# Usage in your configuration:
#
# let
# m3taLib = inputs.m3ta-nixpkgs.lib.${system};
# canonical = m3taLib.agents.loadCanonical { agentsInput = inputs.agents; };
#
# # Render for a specific tool
# rendered = m3taLib.agents.renderForOpencode {
# inherit pkgs canonical;
# modelOverrides = { chiron = "anthropic/claude-sonnet-4"; };
# };
# in { ... }
{lib}: let
# ── Shared helpers ─────────────────────────────────────────────
# Split a rule string on the LAST colon to get { pattern, action }.
# e.g. "rm -rf *:ask" → pattern="rm -rf *", action="ask"
# e.g. "/run/agenix/**:deny" → pattern="/run/agenix/**", action="deny"
parseRule = ruleStr: let
parts = lib.strings.splitString ":" ruleStr;
action = lib.last parts;
pattern = lib.concatStringsSep ":" (lib.init parts);
in {inherit pattern action;};
# ── Shared renderer primitives ──────────────────────────────────
# Render agent files from canonical definitions into a directory.
# Each agent gets a "<name>.md" file containing mkContent name agent.
#
# Args:
# pkgs — Nixpkgs package set with linkFarm
# canonical — Attribute set of agent definitions (keyed by slug)
# mkContent — Function: name: agent → string (file content)
# name — Derivation name (e.g. "opencode-agents")
#
# Returns:
# A store path containing all agent *.md files.
renderAgentFiles = pkgs: canonical: mkContent: name:
pkgs.linkFarm name (
lib.mapAttrsToList (n: a: {
name = "${n}.md";
path = pkgs.writeText "${n}.md" (mkContent n a);
})
canonical
);
agentsLib = {
# ── loadCanonical ─────────────────────────────────────────────
#
# Load canonical agent definitions from the AGENTS flake input.
# Returns the canonical attrset from lib.loadAgents (keyed by slug).
loadCanonical = {agentsInput}: agentsInput.lib.loadAgents;
# ── OpenCode renderer ─────────────────────────────────────────
#
# Produces a directory of agent *.md files suitable for
# ~/.config/opencode/agents/ (system-level)
# .opencode/agents/ (project-level)
#
# Each file has YAML frontmatter (description, mode, optional model,
# optional permission) followed by the agent's systemPrompt content.
# The filename (without .md) becomes the agent name in OpenCode.
renderForOpencode = {
pkgs,
canonical,
modelOverrides ? {},
}: let
# Render one permission section to YAML lines.
# intent-only → single line: " <tool>: <intent>"
# intent+rules → nested block
renderPermSection = tool: section:
if !(section ? rules) || section.rules == []
then [" ${tool}: ${section.intent}"]
else let
parsedRules = map parseRule section.rules;
wildcardLine = " \"*\": ${section.intent}";
ruleLines = map (r: " \"${r.pattern}\": ${r.action}") parsedRules;
in
[" ${tool}:"] ++ [wildcardLine] ++ ruleLines;
renderPermBlock = permissions:
if permissions == {} || permissions == null
then []
else
["permission:"]
++ lib.concatLists (
lib.mapAttrsToList renderPermSection permissions
);
mkFrontmatter = name: agent: let
descLine = "description: \"${agent.description}.\"";
modeLine = "mode: ${agent.mode}";
modelLine =
lib.optionalString
(modelOverrides ? ${name})
"model: ${modelOverrides.${name}}\n";
permBlock = renderPermBlock (agent.permissions or {});
permLines =
if permBlock == []
then ""
else lib.concatStringsSep "\n" permBlock + "\n";
in "---\n${descLine}\n${modeLine}\n${modelLine}${permLines}---\n";
mkAgentContent = name: agent:
(mkFrontmatter name agent) + agent.systemPrompt;
in
renderAgentFiles pkgs canonical mkAgentContent "opencode-agents";
# ── Claude Code renderer ──────────────────────────────────────
#
# Produces a directory containing:
# .claude/agents/<name>.md — one per agent with YAML frontmatter
# .claude/settings.json — permission rules in Claude Code DSL
#
# Claude Code requires:
# - name field: [a-z0-9-]+ (kebab-case)
# - description field: required
# - All agents are subagents (no primary/subagent distinction)
renderForClaudeCode = {
pkgs,
canonical,
modelOverrides ? {},
}: let
# Claude Code permission DSL format: "Tool(pattern)" or just "Tool"
# Canonical bash rules → "Bash(pattern)" entries
# Canonical edit rules → "Edit(pattern)" entries
renderPermAllow = permissions: let
bashRules =
if !(permissions ? bash)
then []
else if permissions.bash.intent == "allow"
then ["Bash"]
else
map
(r: let parsed = parseRule r; in "Bash(${parsed.pattern})")
(lib.filter (r: (parseRule r).action == "allow") (permissions.bash.rules or []));
editRules =
if !(permissions ? edit)
then []
else if permissions.edit.intent == "allow"
then ["Edit"]
else
map
(r: let parsed = parseRule r; in "Edit(${parsed.pattern})")
(lib.filter (r: (parseRule r).action == "allow") (permissions.edit.rules or []));
webRules =
lib.optional (permissions.webfetch.intent or "" == "allow") "WebFetch";
in
bashRules ++ editRules ++ webRules;
renderPermDeny = permissions: let
bashRules =
if !(permissions ? bash)
then []
else
map
(r: let parsed = parseRule r; in "Bash(${parsed.pattern})")
(lib.filter (r: (parseRule r).action == "deny") (permissions.bash.rules or []));
editRules =
if !(permissions ? edit)
then []
else
map
(r: let parsed = parseRule r; in "Edit(${parsed.pattern})")
(lib.filter (r: (parseRule r).action == "deny") (permissions.edit.rules or []));
in
bashRules ++ editRules;
# Build YAML frontmatter for one Claude Code agent .md file.
mkClaudeFrontmatter = name: agent: let
descLine = "description: \"${agent.description}\"";
modelLine =
lib.optionalString
(modelOverrides ? ${name})
"model: ${modelOverrides.${name}}\n";
skillsLine =
if (agent ? skills) && agent.skills != []
then "skills:\n" + lib.concatStringsSep "\n" (map (s: " - ${s}") agent.skills) + "\n"
else "";
in "---\n${descLine}\n${modelLine}${skillsLine}---\n";
mkClaudeAgentContent = name: agent:
(mkClaudeFrontmatter name agent) + agent.systemPrompt;
agentFiles = renderAgentFiles pkgs canonical mkClaudeAgentContent "claude-code-agent-files";
# Build settings.json with permission rules aggregated from all agents.
allAllows = lib.flatten (lib.mapAttrsToList (_: agent: renderPermAllow (agent.permissions or {})) canonical);
allDenies = lib.flatten (lib.mapAttrsToList (_: agent: renderPermDeny (agent.permissions or {})) canonical);
settingsJson = builtins.toJSON {
permissions = {
allow = lib.unique (lib.sort (a: b: a < b) allAllows);
deny = lib.unique (lib.sort (a: b: a < b) allDenies);
};
};
settingsFile = pkgs.writeText "claude-settings.json" settingsJson;
in
pkgs.runCommand "claude-code-agents" {} ''
mkdir -p $out/.claude/agents
cp -r ${agentFiles}/* $out/.claude/agents/
cp ${settingsFile} $out/.claude/settings.json
'';
# ── Pi renderer ───────────────────────────────────────────────
#
# This renderer produces:
# AGENTS.md — concatenated agent descriptions + specialist listing
# SYSTEM.md — primary agent's system prompt (replaces Pi default)
# agents/{name}.md — one per agent for pi-subagents (YAML frontmatter + prompt)
#
# The agents/ files use pi-subagents frontmatter format:
# name, description, tools, extensions, model, thinking, skill,
# output, defaultReads, defaultProgress, interactive, maxSubagentDepth
renderForPi = {
pkgs,
canonical,
modelOverrides ? {},
primaryAgent ? null,
codingRules ? null,
}: let
# Import coding-rules lib for concatRulesMd when codingRules is provided
codingRulesLib = import ./coding-rules.nix {inherit lib;};
# Find the primary agent (there should be exactly one).
primaryAgents = lib.filterAttrs (_: a: a.mode == "primary") canonical;
primaryNames = lib.attrNames primaryAgents;
primaryName =
if primaryAgent != null
then primaryAgent
else if primaryNames == []
then throw "lib.agents.renderForPi: no primary agent found"
else builtins.head primaryNames;
primary = builtins.getAttr primaryName primaryAgents;
# Subagents for the specialist listing.
subagents = lib.filterAttrs (_: a: a.mode != "primary") canonical;
# ── Permission → Pi tool mapping ──────────────────────────────
#
# Pi built-in tools: read, bash, edit, write, grep, find, ls,
# mcp, subagent, web_search, fetch_content, etc.
# Canonical tools: bash, edit, webfetch, websearch, question, external_directory
#
# We map canonical permissions to Pi's tool list.
# intent=allow → include tool; intent=deny → exclude; intent=ask → include (Pi has no ask granularity)
# When specific allow rules exist, the tool is always included (Pi can't restrict by pattern).
piToolsForAgent = agent: let
perms = agent.permissions or {};
tools = [];
# Always available: read (no permission concept in Pi)
addIf = tool: section:
if section.intent == "allow" || section.intent == "ask"
then [tool]
else [];
# bash → bash
withBash = tools ++ (addIf "bash" (perms.bash or {intent = "ask";}));
# edit → edit
withEdit = withBash ++ (addIf "edit" (perms.edit or {intent = "deny";}));
# webfetch → fetch_content
withFetch = withEdit ++ (addIf "fetch_content" (perms.webfetch or {intent = "deny";}));
# websearch → web_search
withSearch = withFetch ++ (addIf "web_search" (perms.websearch or {intent = "deny";}));
in
lib.unique (withSearch ++ ["read" "grep" "find" "ls"]);
# ── Build YAML frontmatter for pi-subagents .md files ──────────
mkPiFrontmatter = name: agent: let
tools = piToolsForAgent agent;
descLine = "description: \"${agent.description}\"";
toolsLine = "tools: ${lib.concatStringsSep ", " tools}";
model =
if modelOverrides ? ${name}
then "model: ${modelOverrides.${name}}"
else "";
skillsLine =
if (agent ? skills) && agent.skills != []
then "skill: ${lib.concatStringsSep ", " agent.skills}"
else "";
in
"---\n"
+ "name: ${name}\n"
+ "${descLine}\n"
+ "${toolsLine}\n"
+ (lib.optionalString (model != "") "${model}\n")
+ (lib.optionalString (skillsLine != "") "${skillsLine}\n")
+ "---\n";
mkPiAgentContent = name: agent:
(mkPiFrontmatter name agent) + agent.systemPrompt;
piAgentFiles = renderAgentFiles pkgs canonical mkPiAgentContent "pi-agent-files";
# ── Build AGENTS.md content ───────────────────────────────────
primaryDn = primary.display_name or primaryName;
specialistEntries = let
mkEntry = name: agent: let
dn = agent.display_name or name;
in
"- **" + dn + "**: " + agent.description;
in
lib.mapAttrsToList mkEntry subagents;
# ── Coding rules section (optional) ────────────────────────
# When codingRules is provided, append selected rules to AGENTS.md.
# codingRules attrset: { agents, languages, concerns, frameworks }
codingRulesSection =
if codingRules != null
then let
section = codingRulesLib.mkRulesMdSection codingRules;
in
if section != ""
then "\n" + section
else ""
else "";
agentsMd =
"# Agent Instructions\n"
+ "\n"
+ "## "
+ primaryDn
+ "\n"
+ "\n"
+ primary.description
+ "\n"
+ "\n"
+ (
if subagents == {}
then ""
else "## Available Specialists\n\n" + lib.concatStringsSep "\n" specialistEntries + "\n"
)
+ codingRulesSection;
agentsMdFile = pkgs.writeText "AGENTS.md" agentsMd;
systemMdFile = pkgs.writeText "SYSTEM.md" primary.systemPrompt;
in
pkgs.runCommand "pi-agents" {} ''
mkdir -p $out/agents
cp ${agentsMdFile} $out/AGENTS.md
cp ${systemMdFile} $out/SYSTEM.md
cp -r ${piAgentFiles}/* $out/agents/
'';
# ── renderForTool dispatcher ──────────────────────────────────
#
# Dispatches to the correct renderer by tool name.
# tool: "opencode" | "claude-code" | "pi"
renderForTool = {
pkgs,
agentsInput,
tool,
modelOverrides ? {},
codingRules ? null,
}: let
canonical = agentsInput.lib.loadAgents;
in
if tool == "opencode"
then
agentsLib.renderForOpencode {
inherit pkgs canonical modelOverrides;
}
else if tool == "claude-code"
then
agentsLib.renderForClaudeCode {
inherit pkgs canonical modelOverrides;
}
else if tool == "pi"
then
agentsLib.renderForPi {
inherit pkgs canonical modelOverrides codingRules;
}
else throw "lib.agents.renderForTool: unknown tool '${tool}'. Must be opencode, claude-code, or pi.";
# ── shellHookForTool ──────────────────────────────────────────
#
# Generates a shellHook string for use in devShells that symlinks
# rendered agent files into the project directory.
#
# Usage:
# devShells.default = pkgs.mkShell {
# shellHook = m3taLib.agents.shellHookForTool {
# inherit pkgs;
# agentsInput = inputs.agents;
# tool = "opencode";
# modelOverrides = { chiron = "anthropic/claude-sonnet-4"; };
# };
# };
shellHookForTool = {
pkgs,
agentsInput,
tool,
modelOverrides ? {},
codingRules ? null,
}: let
rendered = agentsLib.renderForTool {
inherit pkgs agentsInput tool modelOverrides codingRules;
};
in
if tool == "opencode"
then ''
# Agent files for OpenCode
mkdir -p .opencode/agents
ln -sfn ${rendered}/* .opencode/agents/
''
else if tool == "claude-code"
then ''
# Agent files for Claude Code
mkdir -p .claude/agents
ln -sfn ${rendered}/.claude/agents/* .claude/agents/
ln -sfn ${rendered}/.claude/settings.json .claude/settings.json
''
else if tool == "pi"
then ''
# Agent files for Pi
ln -sfn ${rendered}/AGENTS.md AGENTS.md
mkdir -p .pi
ln -sfn ${rendered}/SYSTEM.md .pi/SYSTEM.md
mkdir -p .pi/agents
ln -sfn ${rendered}/agents/* .pi/agents/
''
else throw "lib.agents.shellHookForTool: unknown tool '${tool}'";
};
in
agentsLib
+233
View File
@@ -0,0 +1,233 @@
# Coding rules management utilities
#
# This module provides functions to configure Opencode agent rules across
# multiple projects. Rules are defined in the AGENTS repository and can be
# selectively included based on language, framework, and concerns.
#
# Usage in your configuration:
#
# # In your flake or configuration:
# let
# m3taLib = inputs.m3ta-nixpkgs.lib.${system};
#
# rules = m3taLib.coding-rules.mkCodingRules {
# agents = inputs.agents;
# languages = [ "python" "typescript" ];
# concerns = [ "coding-style" "naming" "documentation" ];
# frameworks = [ "react" "fastapi" ];
# };
# in {
# # Use in your devShell:
# devShells.default = pkgs.mkShell {
# shellHook = rules.shellHook;
# inherit (rules) instructions;
# };
# }
#
# The shellHook creates:
# - A `.opencode-rules/` symlink pointing to the AGENTS repository rules directory
# - A `coding-rules.json` file with a $schema reference and instructions list
# - (Optional) Appends coding rules to `AGENTS.md` for Pi agent discovery
#
# The instructions list contains paths relative to the project root, all prefixed
# with `.opencode-rules/`, making them portable across different project locations.
{lib}: let
# Create Opencode rules configuration from AGENTS repository
#
# Args:
# agents: Path to the AGENTS repository (non-flake input)
# languages: Optional list of language-specific rules to include
# (e.g., [ "python" "typescript" "rust" ])
# concerns: Optional list of concern rules to include
# Default: [ "coding-style" "naming" "documentation" "testing" "git-workflow" "project-structure" ]
# frameworks: Optional list of framework-specific rules to include
# (e.g., [ "react" "fastapi" "django" ])
# extraInstructions: Optional list of additional instruction paths
# (for custom rules outside standard locations)
# forPi: Whether to also append rules to AGENTS.md for Pi agent (default: true)
# Pi discovers AGENTS.md files by walking parent dirs + cwd and concatenates them.
# When enabled, a delimited block is appended to (or created in) AGENTS.md.
#
# Returns:
# An attribute set containing:
# - shellHook: Bash code to create symlink and coding-rules.json
# - instructions: List of rule file paths (relative to project root)
#
# Example:
# mkCodingRules {
# agents = inputs.agents;
# languages = [ "python" ];
# frameworks = [ "fastapi" ];
# }
# # Returns:
# # {
# # shellHook = "...";
# # instructions = [
# # ".opencode-rules/concerns/coding-style.md"
# # ".opencode-rules/concerns/naming.md"
# # ".opencode-rules/concerns/documentation.md"
# # ".opencode-rules/concerns/testing.md"
# # ".opencode-rules/concerns/git-workflow.md"
# # ".opencode-rules/concerns/project-structure.md"
# # ".opencode-rules/languages/python.md"
# # ".opencode-rules/frameworks/fastapi.md"
# # ];
# # }
mkCodingRules = {
agents,
languages ? [],
concerns ? [
"coding-style"
"naming"
"documentation"
"testing"
"git-workflow"
"project-structure"
],
frameworks ? [],
extraInstructions ? [],
rulesDir ? ".opencode-rules",
forPi ? false,
}: let
# Build instructions list by mapping concerns, languages, frameworks to their file paths
# All paths are relative to project root via the rulesDir symlink
instructions =
(map (c: "${rulesDir}/concerns/${c}.md") concerns)
++ (map (l: "${rulesDir}/languages/${l}.md") languages)
++ (map (f: "${rulesDir}/frameworks/${f}.md") frameworks)
++ extraInstructions;
# Generate JSON configuration for coding rules
rulesConfig = {
"$schema" = "https://opencode.ai/config.json";
inherit instructions;
};
# Pi rules content (concatenated markdown) — only computed when forPi is true
piRulesSection =
if forPi
then mkRulesMdSection {inherit agents languages concerns frameworks;}
else "";
# Bash snippet to append rules to AGENTS.md for Pi discovery.
# Uses HTML comment markers for idempotent updates:
# - Removes any existing CODING-RULES block
# - Appends the new block
# - Creates AGENTS.md if it doesn't exist
# Note: Uses plain if-then-else instead of lib.optionalString to avoid
# forcing the `lib` argument (which may come from import <nixpkgs/lib>)
# when forPi is false.
piShellHook =
if forPi && piRulesSection != ""
then ''
# Pi agent: append coding rules to AGENTS.md
if [ -f AGENTS.md ]; then
# Remove existing coding-rules block (if any)
sed -i '/<!-- CODING-RULES:START -->/,/<!-- CODING-RULES:END -->/d' AGENTS.md
# Append new coding-rules block
cat >> AGENTS.md <<'PIRULES_EOF'
${piRulesSection}
PIRULES_EOF
else
# Create AGENTS.md with just the coding rules
cat > AGENTS.md <<'PIRULES_EOF'
${piRulesSection}
PIRULES_EOF
fi
''
else "";
in {
inherit instructions;
# Shell hook to set up rules in the project
# Creates a symlink to the AGENTS rules directory and generates coding-rules.json
# Optionally appends rules to AGENTS.md for Pi agent discovery
shellHook = ''
# Create/update symlink to AGENTS rules directory
ln -sfn ${agents}/rules ${rulesDir}
# Generate coding-rules.json configuration file
cat > coding-rules.json <<'RULES_EOF'
${builtins.toJSON rulesConfig}
RULES_EOF
${piShellHook}
'';
};
# Concatenate selected rule files from the AGENTS repository into a single
# markdown string. Used by Pi (append to AGENTS.md) and could be used by
# other tools that don't support an instructions list.
#
# Args:
# agents: Path to the AGENTS repository (non-flake input)
# languages: Optional list of language-specific rules to include
# concerns: Optional list of concern rules to include
# Default: [ "coding-style" "naming" "documentation" "testing" "git-workflow" "project-structure" ]
# frameworks: Optional list of framework-specific rules to include
#
# Returns: A single concatenated markdown string with all selected rules.
#
# Example:
# concatRulesMd {
# agents = inputs.agents;
# languages = [ "python" ];
# concerns = [ "coding-style" ];
# }
# # Returns: "\n# Coding Style\n\n...python rules...\n"
concatRulesMd = {
agents,
languages ? [],
concerns ? [
"coding-style"
"naming"
"documentation"
"testing"
"git-workflow"
"project-structure"
],
frameworks ? [],
}: let
rulePaths =
(map (c: {
kind = "concerns";
name = c;
})
concerns)
++ (map (l: {
kind = "languages";
name = l;
})
languages)
++ (map (f: {
kind = "frameworks";
name = f;
})
frameworks);
readRule = rule: builtins.readFile "${agents}/rules/${rule.kind}/${rule.name}.md";
ruleContents = map readRule rulePaths;
in
lib.concatStringsSep "\n\n" ruleContents;
# Build a coding rules section suitable for appending to AGENTS.md.
# Wraps concatRulesMd output with a header and HTML comment markers
# for idempotent updates in project-level shellHooks.
#
# Args: Same as concatRulesMd
#
# Returns: A markdown string with start/end markers and a header.
mkRulesMdSection = args: let
content = concatRulesMd args;
in
if builtins.stringLength content == 0
then ""
else ''
<!-- CODING-RULES:START -->
# Coding Rules
${content}
<!-- CODING-RULES:END -->
'';
in {
inherit mkCodingRules concatRulesMd mkRulesMdSection;
}
+15
View File
@@ -0,0 +1,15 @@
# Library of helper functions for m3ta-nixpkgs
# Usage in your configuration:
# let
# m3taLib = inputs.m3ta-nixpkgs.lib.${system};
# in ...
{lib}: {
# Port management utilities
ports = import ./ports.nix {inherit lib;};
# Coding rules injection utilities
coding-rules = import ./coding-rules.nix {inherit lib;};
# Agent configuration management utilities
agents = import ./agents.nix {inherit lib;};
}
+98
View File
@@ -0,0 +1,98 @@
# Port management utilities
#
# This module provides functions to manage service ports across multiple hosts
# in a centralized way. Ports are defined in your configuration and can have
# host-specific overrides.
#
# Usage in your configuration:
#
# # In your flake or configuration, define your ports:
# let
# m3taLib = inputs.m3ta-nixpkgs.lib.${system};
#
# myPorts = {
# ports = {
# nginx = 80;
# grafana = 3000;
# prometheus = 9090;
# homepage = 8080;
# };
# hostPorts = {
# laptop = {
# nginx = 8080; # Override nginx port on laptop
# };
# server = {
# homepage = 3001; # Override homepage port on server
# };
# };
# };
#
# portHelpers = m3taLib.ports.mkPortHelpers myPorts;
# in {
# # Use in your config:
# services.nginx.port = portHelpers.getPort "nginx" "laptop";
# # Returns: 8080 (host-specific override)
#
# services.grafana.port = portHelpers.getPort "grafana" "laptop";
# # Returns: 3000 (default port)
#
# # Get all ports for a specific host (defaults + overrides):
# allLaptopPorts = portHelpers.getHostPorts "laptop";
# # Returns: { nginx = 8080; grafana = 3000; prometheus = 9090; homepage = 8080; }
# }
{lib}: {
# Create port helper functions from a ports configuration
#
# Args:
# portsConfig: An attribute set with structure:
# {
# ports = { service-name = port-number; ... };
# hostPorts = { hostname = { service-name = port-number; ... }; ... };
# }
#
# Returns:
# An attribute set containing helper functions:
# - getPort: Get port for a service with optional host override
# - getHostPorts: Get all ports for a specific host
# - listServices: List all defined services
mkPortHelpers = portsConfig: let
ports = portsConfig.ports or {};
hostPorts = portsConfig.hostPorts or {};
in {
# Get port for a service, with optional host-specific override
#
# Args:
# service: The service name (string)
# host: The hostname (string)
#
# Returns:
# Port number (int) or null if service not found
#
# Example:
# getPort "nginx" "laptop" # Returns host-specific port if defined
# getPort "nginx" null # Returns default port
getPort = service: host:
if host != null && hostPorts ? ${host} && hostPorts.${host} ? ${service}
then hostPorts.${host}.${service}
else ports.${service} or null;
# Get all ports for a specific host (merges defaults with host overrides)
#
# Args:
# host: The hostname (string)
#
# Returns:
# Attribute set of all ports for the host
#
# Example:
# getHostPorts "laptop" # { nginx = 8080; grafana = 3000; ... }
getHostPorts = host:
ports // (hostPorts.${host} or {});
# List all defined service names
#
# Returns:
# List of service names (strings)
listServices = lib.attrNames ports;
};
}
+235
View File
@@ -0,0 +1,235 @@
# Home Manager Modules
User-level configuration modules organized by functional category.
## Structure
```
home-manager/
├── default.nix # Aggregator: imports all categories + ports.nix
├── ports.nix # Port management (HM-specific: generateEnvVars)
├── cli/ # Terminal/CLI tools
│ ├── default.nix # Category aggregator
│ └── zellij-ps.nix
└── coding/ # Development tools
├── default.nix # Category aggregator
├── editors.nix # Neovim + Zed configs
├── opencode.nix # OpenCode non-agent config (theme, plugins, formatter)
└── agents/ # Per-tool agent deployment (canonical TOML → rendered)
├── default.nix
├── opencode.nix # File-based agents + skills + context
├── claude-code.nix # Claude Code agents + settings.json
└── pi.nix # Pi AGENTS.md + SYSTEM.md
```
## Where to Look
| Task | Location |
|------|----------|
| Add CLI module | `cli/<name>.nix`, import in `cli/default.nix` |
| Add coding module | `coding/<name>.nix`, import in `coding/default.nix` |
| Add new category | Create `<category>/default.nix`, import in root `default.nix` |
| Module with host ports | Import `../../lib/ports.nix`, use `mkPortHelpers` |
| Add agent renderer | `coding/agents/<tool>.nix`, import in `coding/agents/default.nix` |
## Option Namespaces
- `cli.*` - CLI tools (e.g., `cli.zellij-ps.enable`)
- `coding.editors.*` - Editor configs (e.g., `coding.editors.neovim.enable`)
- `coding.opencode.*` - OpenCode non-agent config (theme, plugins, formatter)
- `coding.agents.opencode.*` - OpenCode agent deployment (file-based agents)
- `coding.agents.claude-code.*` - Claude Code agent deployment
- `coding.agents.pi.*` - Pi agent deployment
- `m3ta.ports.*` - Port management (shared with NixOS)
## Patterns
**Category aggregator** (`cli/default.nix`):
```nix
{
imports = [
./zellij-ps.nix
# Add new modules here
];
}
```
**Simple module** (zellij-ps):
```nix
options.cli.zellij-ps = {
enable = mkEnableOption "...";
projectFolders = mkOption { type = types.listOf types.path; ... };
};
config = mkIf cfg.enable {
home.packages = [ pkgs.zellij-ps ];
home.sessionVariables.PROJECT_FOLDERS = ...;
};
```
**Multi-config module** (editors.nix):
```nix
config = mkMerge [
(mkIf cfg.neovim.enable { programs.neovim = {...}; })
(mkIf cfg.zed.enable { programs.zed-editor = {...}; })
(mkIf (cfg.neovim.enable || cfg.zed.enable) { home.packages = [...]; })
];
```
## HM vs NixOS Differences
| Feature | Home Manager | NixOS |
|---------|--------------|-------|
| `currentHost` default | `null` (must set) | `config.networking.hostName` |
| `generateEnvVars` | Available | Not available |
| Output file | `~/.config/m3ta/ports.json` | `/etc/m3ta/ports.json` |
| Package access | `pkgs.*` via overlay | `pkgs.*` via overlay |
## Agent Modules
Agent definitions are stored as canonical `agent.toml` + `system-prompt.md` in the
[AGENTS repo](https://code.m3ta.dev/m3tam3re/AGENTS). Renderers in `lib/agents.nix`
transform these into tool-specific configs. Each tool has its own HM sub-module
under `coding/agents/`.
### OpenCode (`coding.agents.opencode`)
Renders file-based agents to `~/.config/opencode/agents/*.md`:
```nix
coding.agents.opencode = {
enable = true;
agentsInput = inputs.agents;
modelOverrides = {
chiron = "anthropic/claude-sonnet-4";
};
externalSkills = [
{ src = inputs.skills-anthropic; }
];
};
```
**Options:** `enable`, `agentsInput`, `modelOverrides`, `externalSkills`
### Claude Code (`coding.agents.claude-code`)
Renders agents to `~/.claude/agents/*.md` + `~/.claude/settings.json`:
```nix
coding.agents.claude-code = {
enable = true;
agentsInput = inputs.agents;
modelOverrides = {};
};
```
**Options:** `enable`, `agentsInput`, `modelOverrides`
### Pi (`coding.agents.pi`)
Renders `AGENTS.md` + `SYSTEM.md` to `~/.pi/agent/`:
```nix
coding.agents.pi = {
enable = true;
agentsInput = inputs.agents;
};
```
**Options:** `enable`, `agentsInput`
### Project-level usage
For per-project agent setup via `flake.nix` + `direnv`:
```nix
m3taLib.agents.shellHookForTool {
inherit pkgs;
agentsInput = inputs.agents;
tool = "opencode";
modelOverrides = { chiron = "anthropic/claude-sonnet-4"; };
};
```
## Migration Guide (OpenCode agents)
The agent system was migrated from embedded `agents.json` to file-based canonical
`agent.toml` definitions. Here is how to migrate your home-manager config.
### What changed
| Before | After |
|--------|-------|
| `coding.opencode.agentsInput` | `coding.agents.opencode.agentsInput` |
| `coding.opencode.externalSkills` | `coding.agents.opencode.externalSkills` |
| Agents embedded in `config.json` | File-based `~/.config/opencode/agents/*.md` |
| Model hardcoded in `agents.json` | Per-machine `modelOverrides` |
| `mkOpencodeRules` | `mkCodingRules` |
### Migration steps
**1. Update home-manager config:**
Move `agentsInput` and `externalSkills` from `coding.opencode` to `coding.agents.opencode`.
Add `modelOverrides` with the models previously hardcoded in agents.json:
```nix
# BEFORE (legacy):
coding.opencode = {
enable = true;
agentsInput = inputs.agents;
externalSkills = [{ src = inputs.skills-anthropic; }];
ohMyOpencodeSettings = { ... };
};
# AFTER (new):
coding.opencode = {
enable = true;
ohMyOpencodeSettings = { ... };
};
coding.agents.opencode = {
enable = true;
agentsInput = inputs.agents;
externalSkills = [{ src = inputs.skills-anthropic; }];
modelOverrides = {
chiron = "zai-coding-plan/glm-5";
"chiron-forge" = "zai-coding-plan/glm-5";
};
};
```
**2. Run `home-manager switch`:**
```bash
home-manager switch --flake .
```
**3. Verify agents are deployed:**
```bash
ls ~/.config/opencode/agents/
# Should show: chiron.md chiron-forge.md hermes.md athena.md apollo.md calliope.md
```
**4. Remove legacy files from AGENTS repo** (after confirming everything works):
```bash
cd /home/m3tam3re/p/AI/AGENTS
rm agents/agents.json
rm prompts/chiron.txt prompts/chiron-forge.txt prompts/hermes.txt \
prompts/athena.txt prompts/apollo.txt prompts/calliope.txt
rmdir prompts/ # if empty
# Also remove lib.agentsJson from flake.nix
```
**5. Final cleanup:** After legacy files are removed from AGENTS repo,
remove `lib.agentsJson` from the AGENTS `flake.nix` (it's only needed for
backward compatibility during the transition).
### Key advantage of the new system
Prompt changes no longer require `home-manager switch`. Since agents are
deployed as file-based `~/.config/opencode/agents/*.md` (symlinks to Nix store),
you only need to edit the `system-prompt.md` in the AGENTS repo, commit, update
the flake lock, and run `home-manager switch`. Or for local development, edit
the file directly and restart the tool.
+8
View File
@@ -0,0 +1,8 @@
# CLI/Terminal-related Home Manager modules
{
imports = [
./rofi-project-opener.nix
./stt-ptt.nix
./zellij-ps.nix
];
}
@@ -0,0 +1,134 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.cli.rofi-project-opener;
# Project directory submodule type
projectDirType = types.submodule {
options = {
path = mkOption {
type = types.str;
description = "Base directory path to scan for project subdirectories.";
example = "~/dev";
};
args = mkOption {
type = types.str;
default = "";
description = "Additional arguments to pass to opencode when launching projects from this directory.";
example = "--agent Planner-Sisyphus";
};
};
};
# Convert projectDirs attrset to JSON for config file
projectDirsJson = builtins.toJSON (
mapAttrs (name: value: {
path = value.path;
args = value.args;
})
cfg.projectDirs
);
in {
options.cli.rofi-project-opener = {
enable = mkEnableOption "Rofi-based project directory launcher";
projectDirs = mkOption {
type = types.attrsOf projectDirType;
default = {
dev = {path = "~/dev";};
projects = {path = "~/projects";};
};
description = ''
Attribute set of base directories to scan for project subdirectories.
Each directory will be scanned for immediate subdirectories (non-hidden).
Projects are displayed as "base_dir/project_name" in rofi.
Each entry can specify:
- path: Base directory path (supports ~ for home directory)
- args: Optional arguments to pass to opencode for projects in this directory
'';
example = literalExpression ''
{
nixpkgs = { path = "~/p/NIX/nixpkgs"; args = "--agent Planner-Sisyphus"; };
dev = { path = "~/dev"; };
work = { path = "~/work"; args = "--agent work-agent"; };
}
'';
};
terminal = mkOption {
type = types.either types.str types.package;
default = "kitty";
description = "Terminal emulator to use for launching opencode. Can be a string or package.";
example = literalExpression "pkgs.alacritty";
};
terminalCommand = mkOption {
type = types.str;
default = "";
description = ''
Custom command to run in the terminal.
Placeholders:
- %s = project path
- %a = project args (from projectDirs.<name>.args)
If empty, defaults to: cd to project, run "opencode %a"
Examples:
- "" (empty) - Uses default: cd to project, run opencode with args
- "opencode %a" - Run opencode with project-specific args
- "nvim" - Open editor (no args)
- "myapp %s %a" - Custom app with path and args
'';
example = literalExpression ''"opencode %a"'';
};
rofiPrompt = mkOption {
type = types.str;
default = "Select project";
description = "Prompt text displayed in rofi.";
example = "Open project:";
};
rofiArgs = mkOption {
type = types.listOf types.str;
default = ["-dmenu" "-i"];
description = ''
Arguments to pass to rofi.
Common options:
- "-dmenu" - Enable dmenu mode (required)
- "-i" - Case-insensitive matching
- "-theme <theme>" - Use specific rofi theme
- "-width <percentage>" - Window width
- "-lines <number>" - Number of visible lines
'';
example = literalExpression ''["-dmenu" "-i" "-theme gruvbox"]'';
};
};
config = mkIf cfg.enable {
home.packages = [pkgs.rofi-project-opener];
# Write JSON config file for project directories
xdg.configFile."rofi-project-opener/projects.json".text = projectDirsJson;
# Write shell config file for other settings
xdg.configFile."rofi-project-opener/config".text = ''
# rofi-project-opener configuration
TERMINAL="${
if isDerivation cfg.terminal
then "${cfg.terminal}/bin/${cfg.terminal.pname or (builtins.baseNameOf (toString cfg.terminal))}"
else cfg.terminal
}"
${optionalString (cfg.terminalCommand != "") ''TERMINAL_CMD="${cfg.terminalCommand}"''}
ROFI_PROMPT="${cfg.rofiPrompt}"
ROFI_ARGS="${escapeShellArgs cfg.rofiArgs}"
'';
};
}
+158
View File
@@ -0,0 +1,158 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.cli.stt-ptt;
# Build stt-ptt package with the selected whisper package
sttPttPackage = pkgs.stt-ptt.override {
whisper-cpp = cfg.whisperPackage;
};
modelDir = "${config.xdg.dataHome}/stt-ptt/models";
modelPath = "${modelDir}/${cfg.model}.bin";
# HuggingFace URL for whisper.cpp models
modelUrl = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${cfg.model}.bin";
in {
options.cli.stt-ptt = {
enable = mkEnableOption "Push to Talk Speech to Text using Whisper";
whisperPackage = mkOption {
type = types.package;
default = pkgs.whisper-cpp;
description = ''
The whisper-cpp package to use. Available options:
Pre-built variants:
- `pkgs.whisper-cpp` - CPU-based inference (default)
- `pkgs.whisper-cpp-vulkan` - Vulkan GPU acceleration
Override options (can be combined):
- `cudaSupport` - NVIDIA CUDA support
- `rocmSupport` - AMD ROCm support
- `vulkanSupport` - Vulkan support
- `coreMLSupport` - Apple CoreML (macOS only)
- `metalSupport` - Apple Metal (macOS ARM only)
Example overrides:
- `pkgs.whisper-cpp.override { cudaSupport = true; }` - NVIDIA GPU
- `pkgs.whisper-cpp.override { rocmSupport = true; }` - AMD GPU
- `pkgs.whisper-cpp.override { vulkanSupport = true; }` - Vulkan
'';
example = literalExpression "pkgs.whisper-cpp.override { cudaSupport = true; }";
};
model = mkOption {
type = types.str;
default = "ggml-large-v3-turbo";
description = ''
The Whisper model to use. Models are downloaded from HuggingFace.
Available models (sorted by size/quality):
- `ggml-tiny` / `ggml-tiny.en` - 75MB, fastest, lowest quality
- `ggml-base` / `ggml-base.en` - 142MB, fast, basic quality
- `ggml-small` / `ggml-small.en` - 466MB, balanced
- `ggml-medium` / `ggml-medium.en` - 1.5GB, good quality
- `ggml-large-v1` - 2.9GB, high quality (original)
- `ggml-large-v2` - 2.9GB, high quality (improved)
- `ggml-large-v3` - 2.9GB, highest quality
- `ggml-large-v3-turbo` - 1.6GB, high quality, optimized speed (recommended)
Models ending in `.en` are English-only and slightly faster for English.
Quantized versions (q5_0, q5_1, q8_0) are also available for reduced size.
'';
example = "ggml-base.en";
};
notifyTimeout = mkOption {
type = types.int;
default = 3000;
description = ''
Notification timeout in milliseconds for the recording indicator.
Set to 0 for persistent notifications.
'';
example = 5000;
};
language = mkOption {
type = types.enum [
"auto"
"en"
"es"
"fr"
"de"
"it"
"pt"
"ru"
"zh"
"ja"
"ko"
"ar"
"hi"
"tr"
"pl"
"nl"
"sv"
"da"
"fi"
"no"
"vi"
"th"
"id"
"uk"
"cs"
];
default = "auto";
description = ''
Language for speech recognition. Use "auto" for automatic language detection,
or specify a language code (ISO 639-1 standard) for better accuracy.
Auto-detection analyzes the audio to determine the spoken language automatically.
Specifying a language can improve accuracy if you know the language in advance.
Common language codes:
- en: English
- es: Spanish
- fr: French
- de: German
- zh: Chinese
- ja: Japanese
- ko: Korean
whisper.cpp supports 100+ languages. See whisper.cpp documentation for the full list.
'';
example = "en";
};
};
config = mkIf cfg.enable {
home.packages = [sttPttPackage];
home.sessionVariables = {
STT_MODEL = modelPath;
STT_LANGUAGE = cfg.language;
STT_NOTIFY_TIMEOUT = toString cfg.notifyTimeout;
};
# Create model directory and download model if not present
home.activation.downloadWhisperModel = lib.hm.dag.entryAfter ["writeBoundary"] ''
MODEL_DIR="${modelDir}"
MODEL_PATH="${modelPath}"
MODEL_URL="${modelUrl}"
$DRY_RUN_CMD mkdir -p "$MODEL_DIR"
if [ ! -f "$MODEL_PATH" ]; then
echo "Downloading Whisper model: ${cfg.model}..."
$DRY_RUN_CMD ${pkgs.curl}/bin/curl -L -o "$MODEL_PATH" "$MODEL_URL" || {
echo "Failed to download model from $MODEL_URL"
echo "Please download manually and place at: $MODEL_PATH"
}
fi
'';
};
}
+45
View File
@@ -0,0 +1,45 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.cli.zellij-ps;
in {
options.cli.zellij-ps = {
enable = mkEnableOption "Zellij Project Selector";
projectFolders = mkOption {
type = types.listOf types.path;
description = "List of project folders for zellij-ps.";
default = ["${config.home.homeDirectory}/projects"];
};
layout = mkOption {
type = types.str;
description = "Layout for zellij";
default = ''
layout {
pane size=1 borderless=true {
plugin location="zellij:tab-bar"
}
pane
pane split_direction="vertical" {
pane
pane command="htop"
}
pane size=2 borderless=true {
plugin location="zellij:status-bar"
}
}
'';
};
};
config = mkIf cfg.enable {
home.packages = [pkgs.zellij-ps];
home.sessionVariables.PROJECT_FOLDERS = lib.concatStringsSep ":" cfg.projectFolders;
home.file.".config/zellij/layouts/zellij-ps.kdl".text = cfg.layout;
};
}
@@ -0,0 +1,94 @@
{
config,
lib,
pkgs,
...
}: {
imports = [
./shared/default.nix
];
options.coding.agents.claude-code = let
shared = import ./shared/shared-options.nix {inherit lib;};
mcpCfg = config.programs.mcp or null;
in
with lib; {
enable = mkEnableOption "Claude Code agent management via canonical agent.toml definitions";
agentsInput = shared.mkAgentsInputOption ''
The `agents` flake input (your personal AGENTS repo).
When set, agents are rendered from canonical agent.toml files
and symlinked to ~/.claude/agents/.
'';
modelOverrides = shared.mkModelOverridesOption;
externalSkills = shared.externalSkillsOption;
mcpServers = mkOption {
type = types.attrsOf types.anything;
default =
if mcpCfg != null
then mcpCfg.servers
else {};
defaultText = literalExpression "config.programs.mcp.servers";
description = ''
MCP server configurations for Claude Code.
Merged into ~/.claude/settings.json alongside permissions.
Automatically inherits from config.programs.mcp.servers.
'';
};
};
config = with lib; let
shared = import ./shared/shared-options.nix {inherit lib;};
cfg = config.coding.agents.claude-code;
agentsLib = (import ../../../../lib {inherit lib;}).agents;
in
mkIf cfg.enable (let
# Rendered agents + permissions (only if agentsInput is set)
rendered = mkIf (cfg.agentsInput != null) (
agentsLib.renderForClaudeCode {
inherit pkgs;
canonical = cfg.agentsInput.lib.loadAgents;
modelOverrides = cfg.modelOverrides;
}
);
# Merge MCP servers into the rendered settings.json.
# The renderer produces { permissions: { allow, deny } }.
# We add mcpServers on top.
settingsJson =
if cfg.agentsInput != null
then let
renderedSettings = builtins.fromJSON (builtins.readFile "${rendered}/.claude/settings.json");
withMcp =
if cfg.mcpServers != {}
then renderedSettings // {mcpServers = cfg.mcpServers;}
else renderedSettings;
in
pkgs.writeText "claude-settings.json" (builtins.toJSON withMcp)
else if cfg.mcpServers != {}
then pkgs.writeText "claude-settings.json" (builtins.toJSON {mcpServers = cfg.mcpServers;})
else null;
in {
# Rendered agent files symlinked to ~/.claude/agents/
home.file.".claude/agents" = mkIf (cfg.agentsInput != null) {
source = "${rendered}/.claude/agents";
};
# Skills (merged from personal AGENTS repo + optional external skills)
home.file.".claude/skills" = mkIf (cfg.agentsInput != null) {
source = cfg.agentsInput.lib.mkSkills {
inherit pkgs;
customSkills = "${cfg.agentsInput}/skills";
externalSkills = shared.mapExternalSkills cfg.externalSkills;
};
};
# Rendered settings.json with permissions + MCP servers
home.file.".claude/settings.json" = mkIf (settingsJson != null) {
source = "${settingsJson}";
};
});
}
@@ -0,0 +1,39 @@
# Per-tool agent sub-modules
# Each module handles rendering canonical agent.toml definitions
# for a specific AI coding tool.
#
# Also provides the shared coding.agents.skills submodule that writes
# ~/.agents/skills — the central skills directory used by Pi, OpenCode, etc.
{
config,
lib,
pkgs,
...
}: let
shared = import ./shared/shared-options.nix {inherit lib;};
cfg = config.coding.agents.skills;
mkIf = lib.mkIf;
in {
imports = [
./opencode.nix
./claude-code.nix
./pi.nix
];
options.coding.agents.skills = {
agentsInput = shared.mkAgentsInputOption ''
The `agents` flake input (your personal AGENTS repo).
When set, skills are symlinked to ~/.agents/skills.
'';
externalSkills = shared.externalSkillsOption;
};
config = mkIf (cfg.agentsInput != null) {
home.file.".agents/skills".source = cfg.agentsInput.lib.mkSkills {
inherit pkgs;
customSkills = "${cfg.agentsInput}/skills";
externalSkills = shared.mapExternalSkills cfg.externalSkills;
};
};
}
@@ -0,0 +1,54 @@
{
config,
lib,
pkgs,
...
}: {
imports = [
./shared/default.nix
];
options.coding.agents.opencode = let
shared = import ./shared/shared-options.nix {inherit lib;};
in
with lib; {
enable = mkEnableOption "OpenCode agent management via canonical agent.toml definitions";
agentsInput = shared.mkAgentsInputOption ''
The `agents` flake input (your personal AGENTS repo).
When set, agents are rendered from canonical agent.toml files
and symlinked to ~/.config/opencode/agents/.
'';
modelOverrides = shared.mkModelOverridesOption;
};
config = with lib; let
shared = import ./shared/shared-options.nix {inherit lib;};
cfg = config.coding.agents.opencode;
in
mkIf cfg.enable {
# Rendered agent files symlinked to ~/.config/opencode/agents/
xdg.configFile."opencode/agents" = let
agentsLib = (import ../../../../lib {inherit lib;}).agents;
in
mkIf (cfg.agentsInput != null) {
source = agentsLib.renderForOpencode {
inherit pkgs;
canonical = cfg.agentsInput.lib.loadAgents;
modelOverrides = cfg.modelOverrides;
};
};
# Static config dirs from AGENTS repo
xdg.configFile."opencode/context" = mkIf (cfg.agentsInput != null) {
source = "${cfg.agentsInput}/context";
};
xdg.configFile."opencode/commands" = mkIf (cfg.agentsInput != null) {
source = "${cfg.agentsInput}/commands";
};
xdg.configFile."opencode/prompts" = mkIf (cfg.agentsInput != null) {
source = "${cfg.agentsInput}/prompts";
};
};
}
+357
View File
@@ -0,0 +1,357 @@
{
config,
lib,
pkgs,
...
}: {
imports = [
./shared/default.nix
];
options.coding.agents.pi = let
shared = import ./shared/shared-options.nix {inherit lib;};
mcpCfg = config.programs.mcp or null;
in
with lib; {
enable = mkEnableOption "Pi agent management via canonical agent.toml definitions";
mcpServers = mkOption {
type = types.attrsOf types.anything;
default =
if mcpCfg != null
then mcpCfg.servers
else {};
defaultText = literalExpression "config.programs.mcp.servers";
description = ''
MCP server configurations for Pi (pi-mcp-adapter).
Written to ~/.pi/agent/mcp.json.
Automatically inherits from config.programs.mcp.servers.
'';
};
agentsInput = shared.mkAgentsInputOption ''
The `agents` flake input (your personal AGENTS repo).
When set, the primary agent's system prompt is rendered as SYSTEM.md,
all agents are listed in AGENTS.md, and subagent .md files are deployed.
'';
modelOverrides = shared.mkModelOverridesOption;
primaryAgent = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Override which canonical agent is used as primary for SYSTEM.md.
When null, the first agent with mode="primary" is used.
'';
};
codingRules = mkOption {
type = types.nullOr (types.submodule {
options = {
languages = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Language-specific coding rules to include
(e.g. [ "python" "typescript" "nix" ]).
Rule files are read from the AGENTS repo's rules/languages/ directory.
'';
};
concerns = mkOption {
type = types.listOf types.str;
default = [
"coding-style"
"naming"
"documentation"
"testing"
"git-workflow"
"project-structure"
];
description = ''
Concern rules to include from the AGENTS repo's rules/concerns/ directory.
'';
};
frameworks = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Framework-specific coding rules to include
(e.g. [ "react" "fastapi" ]).
Rule files are read from the AGENTS repo's rules/frameworks/ directory.
'';
};
};
});
default = null;
description = ''
Coding rules to inject into ~/.pi/agent/AGENTS.md.
Rules are read from the AGENTS repository and appended as markdown sections.
Requires agentsInput to be set.
'';
example = literalExpression ''
{
languages = [ "python" "typescript" ];
concerns = [ "coding-style" "testing" ];
frameworks = [ "fastapi" ];
}
'';
};
settings = mkOption {
type = types.submodule {
freeformType = types.attrsOf types.anything;
options = {
packages = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Pi packages to install (npm:, git:, or local paths).
These are written to ~/.pi/agent/settings.json.
'';
};
defaultProvider = mkOption {
type = types.nullOr types.str;
default = null;
description = "Default LLM provider (e.g. 'anthropic', 'openai', 'zai').";
};
defaultModel = mkOption {
type = types.nullOr types.str;
default = null;
description = "Default model ID.";
};
defaultThinkingLevel = mkOption {
type = types.nullOr (types.enum ["off" "minimal" "low" "medium" "high" "xhigh"]);
default = null;
description = "Default extended thinking level.";
};
theme = mkOption {
type = types.nullOr types.str;
default = null;
description = "Pi theme name.";
};
hideThinkingBlock = mkOption {
type = types.nullOr types.bool;
default = null;
description = "Hide thinking blocks in output.";
};
quietStartup = mkOption {
type = types.nullOr types.bool;
default = null;
description = "Hide startup header.";
};
compaction = mkOption {
type = types.nullOr (types.submodule {
options = {
enabled = mkOption {
type = types.nullOr types.bool;
default = null;
};
reserveTokens = mkOption {
type = types.nullOr types.int;
default = null;
};
keepRecentTokens = mkOption {
type = types.nullOr types.int;
default = null;
};
};
});
default = null;
description = "Auto-compaction settings.";
};
enabledModels = mkOption {
type = types.nullOr (types.listOf types.str);
default = null;
description = "Model patterns for Ctrl+P cycling.";
};
sessionDir = mkOption {
type = types.nullOr types.str;
default = null;
description = "Directory where session files are stored.";
};
extensions = mkOption {
type = types.listOf types.str;
default = [];
description = "Local extension file paths or directories.";
};
skills = mkOption {
type = types.listOf types.str;
default = [];
description = "Local skill file paths or directories.";
};
};
};
default = {};
description = ''
Pi settings written to ~/.pi/agent/settings.json.
Only non-null values are included in the generated JSON.
See pi docs/settings.md for all options.
'';
};
# ── Pi Guardrails ─────────────────────────────────────────────
guardrails = mkOption {
type = types.nullOr (types.submodule {
options = {
enable =
mkEnableOption
("Generate ~/.pi/agent/extensions/guardrails.json for pi-guardrails. "
+ "Adds @aliou/pi-guardrails to packages automatically.");
config = mkOption {
type = types.attrsOf types.anything;
default = {};
description = ''
Guardrails configuration written to ~/.pi/agent/extensions/guardrails.json.
See https://github.com/aliou/pi-guardrails for config schema.
IMPORTANT: Path access checks are lexical (not symlink-safe).
Local project .pi/extensions/guardrails.json can override same rule IDs
(memory > local > global > defaults). For immutable global policies,
consider a wrapper or upstream patch.
'';
};
};
});
default = null;
description = ''
Pi Guardrails security configuration.
Generates ~/.pi/agent/extensions/guardrails.json when enabled.
The @aliou/pi-guardrails package is added to settings.packages automatically.
'';
};
};
config = with lib; let
shared = import ./shared/shared-options.nix {inherit lib;};
cfg = config.coding.agents.pi;
in
mkIf cfg.enable (let
# Build settings.json by filtering out null values recursively
filterNulls = attrs:
lib.filterAttrs (_: v: v != null) (
builtins.mapAttrs (_: v:
if builtins.isAttrs v
then let
filtered = filterNulls v;
in
if filtered == {}
then null
else filtered
else v)
attrs
);
# Base settings (already filtered)
piSettings = filterNulls cfg.settings;
# Guardrails package to inject when guardrails is enabled
guardrailsPackage = "npm:@aliou/pi-guardrails@0.11.1";
# Guardrails config (only when guardrails is enabled)
guardrailsJson =
if (cfg.guardrails != null && cfg.guardrails.enable)
then builtins.toJSON cfg.guardrails.config
else null;
# Merge guardrails package into settings.packages when guardrails is enabled
piSettingsWithGuardrails = let
baseSettings = cfg.settings;
basePackages = baseSettings.packages or [];
hasGuardrailsPackage =
lib.any
(p:
lib.hasPrefix "npm:@aliou/pi-guardrails" p
|| (lib.hasPrefix "git:" p && lib.hasSuffix "/pi-guardrails" p))
basePackages;
packagesWithGuardrails =
if (cfg.guardrails != null && cfg.guardrails.enable && !hasGuardrailsPackage)
then basePackages ++ [guardrailsPackage]
else basePackages;
in
if packagesWithGuardrails != basePackages
then filterNulls (baseSettings // {packages = packagesWithGuardrails;})
else piSettings;
# Coding rules config for renderForPi (only when both agentsInput and codingRules are set)
piCodingRules =
if cfg.agentsInput != null && cfg.codingRules != null
then cfg.codingRules // {agents = cfg.agentsInput;}
else null;
# Rendered agents (only computed when agentsInput is set)
rendered =
if cfg.agentsInput != null
then
(import ../../../../lib {inherit lib;}).agents.renderForPi {
inherit pkgs;
canonical = cfg.agentsInput.lib.loadAgents;
modelOverrides = cfg.modelOverrides;
primaryAgent = cfg.primaryAgent;
codingRules = piCodingRules;
}
else null;
# Dynamic home.file entries for agent .md files
agentFiles =
if cfg.agentsInput != null
then let
agentNames = builtins.attrNames cfg.agentsInput.lib.loadAgents;
in
builtins.listToAttrs (
map (name: {
name = ".pi/agent/agents/${name}.md";
value = {source = "${rendered}/agents/${name}.md";};
})
agentNames
)
else {};
in {
home.file = mkMerge [
# ── MCP servers from programs.mcp → ~/.pi/agent/mcp.json ───────
(mkIf (cfg.mcpServers != {}) {
".pi/agent/mcp.json".text = builtins.toJSON {mcpServers = cfg.mcpServers;};
".pi/agent/mcp.json".force = true;
})
# ── ~/.pi/agent/settings.json ──────────────────────────────────
{
".pi/agent/settings.json".text = builtins.toJSON piSettingsWithGuardrails;
".pi/agent/settings.json".force = true;
}
# ── pi-guardrails config ─────────────────────────────────────
(mkIf (guardrailsJson != null) {
".pi/agent/extensions/guardrails.json".text = guardrailsJson;
".pi/agent/extensions/guardrails.json".force = true;
})
# ── AGENTS.md — agent descriptions and specialist listing ──────
(mkIf (cfg.agentsInput != null) {
".pi/agent/AGENTS.md".source = "${rendered}/AGENTS.md";
})
# ── SYSTEM.md — primary agent's system prompt ──────────────────
(mkIf (cfg.agentsInput != null) {
".pi/agent/SYSTEM.md".source = "${rendered}/SYSTEM.md";
})
# ── Agents — pi-subagents .md files ────────────────────────────
agentFiles
];
});
}
@@ -0,0 +1,7 @@
# Shared agent module exports
# Imports all shared modules for the coding.agents namespace.
{
imports = [
./git-identity.nix
];
}
@@ -0,0 +1,64 @@
# Git identity module for agent commits.
# Sets GIT_AUTHOR_*, GIT_COMMITTER_*, and GIT_SSH_COMMAND environment variables.
{
pkgs,
lib,
config,
...
}: let
cfg = config.coding.agents.gitIdentity;
in {
options.coding.agents.gitIdentity = {
enable = lib.mkEnableOption ''
Agent Git identity for commits. When enabled, sets GIT_AUTHOR_* and
GIT_COMMITTER_* environment variables for consistent bot identity.
'';
name = lib.mkOption {
type = lib.types.str;
default = "m3ta-chiron";
description = "Git user name for agent commits.";
example = "m3ta-chiron";
};
email = lib.mkOption {
type = lib.types.str;
default = "m3ta-chiron@agentmail.to";
description = "Git email for agent commits.";
example = "m3ta-chiron@agentmail.to";
};
signingKey = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
Optional GPG signing key for verified commits.
Set to null to disable signing.
'';
example = "/home/user/.gnupg/sign_key.gpg";
};
sshKey = lib.mkOption {
type = lib.types.path;
description = ''
Path to SSH private key for git push authentication.
Use agenix-managed paths like /run/agenix/m3ta-chiron-ssh-key
for secure secret management.
'';
example = "/run/agenix/m3ta-chiron-ssh-key";
};
};
config = lib.mkIf cfg.enable {
home.sessionVariables = {
# Git author/committer identity
GIT_AUTHOR_NAME = cfg.name;
GIT_AUTHOR_EMAIL = cfg.email;
GIT_COMMITTER_NAME = cfg.name;
GIT_COMMITTER_EMAIL = cfg.email;
# SSH command for git push
GIT_SSH_COMMAND = "ssh -i ${cfg.sshKey} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new";
};
};
}
@@ -0,0 +1,77 @@
# Shared option definitions for agent modules.
# Prevents copy-pasting the externalSkills submodule across opencode/claude-code/pi.
{lib}: let
inherit (lib) mkOption mkEnableOption types literalExpression;
in {
# Common agentsInput option used by all agent modules.
mkAgentsInputOption = description:
mkOption {
type = types.nullOr types.anything;
default = null;
inherit description;
};
# Common modelOverrides option.
mkModelOverridesOption = mkOption {
type = types.attrsOf types.str;
default = {};
description = ''
Per-agent model overrides. Maps agent slug to model string.
Example: { chiron = "anthropic/claude-sonnet-4"; }
'';
example = literalExpression ''
{
chiron = "anthropic/claude-sonnet-4";
"chiron-forge" = "anthropic/claude-sonnet-4";
}
'';
};
# External skills submodule — used by opencode, claude-code, and pi modules.
externalSkillsOption = mkOption {
type = types.listOf (types.submodule {
options = {
src = mkOption {
type = types.anything;
description = "Flake input pointing to a skills repository root.";
};
skillsDir = mkOption {
type = types.str;
default = "skills";
description = ''
Subdirectory inside src that contains skill folders.
'';
};
selectSkills = mkOption {
type = types.nullOr (types.listOf types.str);
default = null;
description = ''
List of skill names to cherry-pick from this source.
null means include every skill found in skillsDir.
'';
};
};
});
default = [];
description = ''
External skill sources passed to mkSkills.
Each entry maps directly to an element of the externalSkills
list accepted by the AGENTS flake's lib.mkSkills.
'';
example = literalExpression ''
[
{ src = inputs.skills-anthropic; selectSkills = [ "claude-api" ]; }
{ src = inputs.basecamp; }
]
'';
};
# Helper to map externalSkills from module config to mkSkills format.
mapExternalSkills = cfgEntries:
map (
entry:
{inherit (entry) src skillsDir;}
// lib.optionalAttrs (entry.selectSkills != null) {inherit (entry) selectSkills;}
)
cfgEntries;
}
+8
View File
@@ -0,0 +1,8 @@
# Coding-related Home Manager modules
{
imports = [
./editors.nix
./opencode.nix
./agents
];
}
+240
View File
@@ -0,0 +1,240 @@
{
config,
lib,
options,
pkgs,
...
}:
with lib; let
cfg = config.coding.editors;
# home-manager 26.05+ renamed extraLuaConfig → initLua.
# On stable 25.11 initLua does not exist; fall back to extraLuaConfig.
hasInitLua = options.programs.neovim ? initLua;
lazyVimConfig = ''
-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable",
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
-- Bootstrap LazyVim via lazy.nvim
-- Docs: https://github.com/folke/lazy.nvim and https://www.lazyvim.org/
require("lazy").setup({
spec = {
{ "LazyVim/LazyVim", import = "lazyvim.plugins" },
{ import = "lazyvim.plugins.extras.lang.typescript" },
{ import = "lazyvim.plugins.extras.lang.python" },
{ import = "lazyvim.plugins.extras.lang.go" },
{ import = "lazyvim.plugins.extras.lang.nix" },
{ import = "lazyvim.plugins.extras.lang.rust" },
{ import = "lazyvim.plugins.extras.lang.nushell" },
{ "Mofiqul/dracula.nvim" },
},
defaults = { lazy = false, version = false },
install = { colorscheme = { "dracula", "tokyonight", "habamax" } },
checker = { enabled = false },
performance = {
rtp = {
disabled_plugins = {
"gzip", "tarPlugin", "tohtml", "tutor", "zipPlugin",
},
},
},
})
vim.o.termguicolors = true
vim.cmd.colorscheme("dracula")
'';
in {
options.coding.editors = {
neovim = {
enable = mkEnableOption "neovim with LazyVim configuration";
};
zed = {
enable = mkEnableOption "zed editor with custom configuration";
};
};
config = mkMerge [
# Neovim configuration
(mkIf cfg.neovim.enable (mkMerge [
{
programs.neovim = {
enable = true;
defaultEditor = true;
viAlias = true;
vimAlias = true;
vimdiffAlias = true;
withNodeJs = true;
withPython3 = true;
};
}
# Use initLua on HM 26.05+ (unstable), extraLuaConfig on HM ≤ 25.11 (stable)
(
if hasInitLua
then {programs.neovim.initLua = lazyVimConfig;}
else {programs.neovim.extraLuaConfig = lazyVimConfig;}
)
]))
# Zed editor configuration
(mkIf cfg.zed.enable {
programs.zed-editor = {
enable = true;
userSettings = {
# CLI Behavior
cli_default_open_behavior = "existing_window";
# UI and Theme
theme = "Dracula";
ui_font_size = 16;
buffer_font_size = 16;
buffer_font_family = "FiraCode Nerd Font";
# Agent UI
agent_ui_font_size = 24.0;
# Editor Behavior
vim_mode = true;
auto_update = false;
format_on_save = "on";
load_direnv = "shell_hook";
# AI Features
features = {
copilot = false;
inline_prediction_provider = "zed";
};
edit_predictions = {
mode = "subtle";
provider = "zed";
};
show_edit_predictions = true;
agent_servers = {
"pi-acp" = {
type = "registry";
};
};
agent = {
dock = "right";
default_profile = "ask";
version = "2";
default_model = {
provider = "anthropic";
model = "claude-4";
};
};
# Language Models
language_models = {
anthropic = {
api_url = "https://api.anthropic.com";
};
openai = {
api_url = "https://api.openai.com/v1";
};
ollama = {
api_url = "http://localhost:11434";
};
};
# Languages Configuration
languages = {
Nix = {
language_servers = ["nixd"];
formatter = {
external = {
command = "alejandra";
arguments = [
"-q"
"-"
];
};
};
};
Python = {
language_servers = ["pyrefly"];
formatter = {
external = {
command = "black";
arguments = ["-"];
};
};
};
};
# LSP Configuration
lsp = {
rust-analyzer = {
initialization_options = {
check = {
command = "clippy";
};
};
};
rust_analyzer = {
binary = {
path_lookup = true;
};
};
pyrefly = {
binary = {
arguments = ["--lsp"];
};
};
};
# Panel Layout
project_panel = {
dock = "left";
};
outline_panel = {
dock = "left";
};
collaboration_panel = {
dock = "left";
};
git_panel = {
dock = "left";
};
# Privacy
telemetry = {
metrics = false;
};
};
};
})
# SSH Connections
(mkIf cfg.zed.enable {
programs.zed-editor.userSettings.ssh_connections = [
{
nickname = "m3-atlas";
host = "152.53.85.162";
args = ["-i" "~/.ssh/m3tam3re"];
}
{
nickname = "self-host-playbook";
host = "95.217.189.186";
port = 2222;
args = ["-i" "~/.ssh/self-host-playbook"];
projects = [
{
paths = ["/etc/nixos/current-systemconfig"];
}
];
}
{
nickname = "m3-daedalus";
host = "192.168.1.152";
port = 22;
args = ["-i" "~/.ssh/m3tam3re"];
projects = [
{
paths = ["/home/m3tam3re/home-config"];
}
];
}
];
})
# Common packages (always installed if either editor is enabled)
(mkIf (cfg.neovim.enable || cfg.zed.enable) {
home.packages = with pkgs; [zig];
})
];
}
+86
View File
@@ -0,0 +1,86 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.coding.opencode;
in {
options.coding.opencode = {
enable = mkEnableOption "opencode AI coding assistant";
ohMyOpencodeSettings = mkOption {
type = types.attrs;
default = {};
description = ''
Attributes merged (via recursiveUpdate) on top of the default
oh-my-opencode.json. Use this to set provider-specific model
assignments per machine.
'';
example = literalExpression ''
{
agents.sisyphus.model = "anthropic/claude-opus-4-5";
categories.ultrabrain.model = "anthropic/claude-opus-4-5";
}
'';
};
extraSettings = mkOption {
type = types.attrs;
default = {};
description = ''
Extra opencode settings merged (via mkMerge) into
programs.opencode.settings. Use this to add provider
configuration that is specific to a machine or organisation.
'';
example = literalExpression ''
{
provider.anthropic = {
name = "Anthropic";
models."claude-opus-4-5" = { limit.context = 200000; };
};
}
'';
};
extraPlugins = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Additional opencode plugins to add to the plugin list.
Each entry is a path or package name passed to opencode's plugin array.
'';
};
};
config = mkIf cfg.enable {
programs.opencode = {
enable = true;
enableMcpIntegration = true;
settings = mkMerge [
{
theme = "opencode";
plugin = ["oh-my-openagent"] ++ cfg.extraPlugins;
formatter = {
alejandra = {
command = ["alejandra" "-q" "-"];
extensions = [".nix"];
};
};
}
cfg.extraSettings
];
};
home.file.".config/opencode/oh-my-opencode.json".text = builtins.toJSON (
recursiveUpdate
{
"$schema" = "https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json";
google_auth = false;
disabled_mcps = ["context7" "websearch"];
}
cfg.ohMyOpencodeSettings
);
};
}
+8
View File
@@ -0,0 +1,8 @@
# Home Manager modules organized by category
{
imports = [
./cli
./coding
./ports.nix
];
}
+159
View File
@@ -0,0 +1,159 @@
# Home Manager Module for Port Management
#
# This module provides centralized port management for Home Manager configurations.
# Define ports once and use them consistently across user services, with support
# for host-specific overrides.
#
# Usage in your Home Manager configuration:
#
# # In your home.nix or flake:
# imports = [ inputs.m3ta-nixpkgs.homeManagerModules.default ];
#
# m3ta.ports = {
# enable = true;
#
# # Define your default ports
# definitions = {
# vscodium = 8080;
# jupyter = 8888;
# dev-server = 3000;
# local-api = 8000;
# docs-preview = 4000;
# };
#
# # Define host-specific overrides
# hostOverrides = {
# laptop = {
# dev-server = 3001;
# vscodium = 8081;
# };
# desktop = {
# jupyter = 9999;
# };
# };
#
# # Set the current hostname
# currentHost = "laptop"; # Or use config.networking.hostName if available
# };
#
# # Use ports in your configuration:
# home.file.".config/myapp/config.json".text = builtins.toJSON {
# port = config.m3ta.ports.get "dev-server";
# };
#
# # Generate environment variables:
# home.sessionVariables = {
# DEV_SERVER_PORT = toString (config.m3ta.ports.get "dev-server");
# JUPYTER_PORT = toString (config.m3ta.ports.get "jupyter");
# };
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.m3ta.ports;
portsLib = import ../../lib/ports.nix {inherit lib;};
portHelpers =
if cfg.enable
then
portsLib.mkPortHelpers {
ports = cfg.definitions;
hostPorts = cfg.hostOverrides;
}
else null;
in {
options.m3ta.ports = {
enable = mkEnableOption "centralized port management for Home Manager";
definitions = mkOption {
type = types.attrsOf types.port;
default = {};
description = "Default port definitions for user services.";
};
hostOverrides = mkOption {
type = types.attrsOf (types.attrsOf types.port);
default = {};
description = "Host-specific port overrides.";
};
currentHost = mkOption {
type = types.nullOr types.str;
default = null;
description = "Hostname to use for port resolution.";
};
# Internal computed options
get = mkOption {
type = types.raw;
readOnly = true;
internal = true;
};
getForHost = mkOption {
type = types.raw;
readOnly = true;
internal = true;
};
all = mkOption {
type = types.attrsOf types.port;
readOnly = true;
internal = true;
};
allForHost = mkOption {
type = types.raw;
readOnly = true;
internal = true;
};
services = mkOption {
type = types.listOf types.str;
readOnly = true;
internal = true;
};
# Env var generation
generateEnvVars = mkOption {
type = types.bool;
default = false;
description = "Generate environment variables for all ports.";
};
envVarPrefix = mkOption {
type = types.str;
default = "PORT_";
description = "Prefix for generated environment variables.";
};
};
config = mkIf cfg.enable {
m3ta.ports.get = service: portHelpers.getPort service cfg.currentHost;
m3ta.ports.getForHost = host: service: portHelpers.getPort service host;
m3ta.ports.all = portHelpers.getHostPorts cfg.currentHost;
m3ta.ports.allForHost = portHelpers.getHostPorts;
m3ta.ports.services = portHelpers.listServices;
home.sessionVariables = mkIf cfg.generateEnvVars (
let
toEnvVarName = service:
cfg.envVarPrefix + (lib.toUpper (builtins.replaceStrings ["-"] ["_"] service));
in
builtins.listToAttrs (
map (service: {
name = toEnvVarName service;
value = toString (cfg.get service);
})
cfg.services
)
);
home.file.".config/m3ta/ports.json".text = builtins.toJSON {
hostname = cfg.currentHost;
ports = cfg.all;
allDefinitions = cfg.definitions;
hostOverrides = cfg.hostOverrides;
};
};
}
+30
View File
@@ -0,0 +1,30 @@
# NixOS Modules
# Import this in your NixOS configuration with:
# imports = [ inputs.m3ta-nixpkgs.nixosModules.default ];
{
config,
lib,
pkgs,
...
}: {
# This is the main entry point for all custom NixOS modules
# Add your custom modules here as imports or inline definitions
imports = [
./mem0.nix
./ports.nix
# Example: ./my-service.nix
# Add more module files here as you create them
];
# You can also define inline options here
# options = {
# m3ta = {
# # Your custom options
# };
# };
# config = {
# # Your custom configuration
# };
}
+363
View File
@@ -0,0 +1,363 @@
# NixOS Module for Mem0 REST API Server
#
# This module provides a systemd service for the Mem0 REST API server,
# allowing you to run mem0 as a system service with configurable vector storage.
#
# Usage in your NixOS configuration:
#
# # In your flake.nix or configuration.nix:
# imports = [ inputs.m3ta-nixpkgs.nixosModules.default ];
#
# m3ta.mem0 = {
# enable = true;
# port = 8000;
# host = "127.0.0.1";
#
# # LLM Configuration
# llm = {
# provider = "openai";
# apiKeyFile = "/run/secrets/openai-api-key"; # Use agenix or sops-nix
# model = "gpt-4";
# };
#
# # Vector Storage Configuration
# vectorStore = {
# provider = "qdrant"; # or "chroma", "pinecone", etc.
# config = {
# host = "localhost";
# port = 6333;
# };
# };
#
# # Optional: Environment variables
# environmentFile = "/etc/mem0/environment";
# };
#
# Using with m3ta.ports (recommended):
#
# m3ta.ports = {
# enable = true;
# definitions = { mem0 = 8000; };
# hostOverrides.laptop = { mem0 = 8080; };
# currentHost = config.networking.hostName;
# };
#
# m3ta.mem0 = {
# enable = true;
# port = config.m3ta.ports.get "mem0"; # Automatically uses host-specific port
# };
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.m3ta.mem0;
# Python environment with mem0
pythonEnv = pkgs.python3.withPackages (ps:
with ps; [
cfg.package
]);
# Convert vector store config to environment variables
vectorStoreEnv =
if cfg.vectorStore.provider == "qdrant"
then {
MEM0_VECTOR_PROVIDER = "qdrant";
QDRANT_HOST = cfg.vectorStore.config.host or "localhost";
QDRANT_PORT = toString (cfg.vectorStore.config.port or 6333);
QDRANT_COLLECTION = cfg.vectorStore.config.collection_name or "mem0_memories";
}
else if cfg.vectorStore.provider == "pgvector"
then {
MEM0_VECTOR_PROVIDER = "pgvector";
POSTGRES_HOST = cfg.vectorStore.config.host or "localhost";
POSTGRES_PORT = toString (cfg.vectorStore.config.port or 5432);
POSTGRES_DB = cfg.vectorStore.config.dbname or "postgres";
POSTGRES_USER = cfg.vectorStore.config.user or "postgres";
POSTGRES_PASSWORD = cfg.vectorStore.config.password or "postgres";
POSTGRES_COLLECTION = cfg.vectorStore.config.collection_name or "mem0_memories";
}
else if cfg.vectorStore.provider == "chroma"
then {
MEM0_VECTOR_PROVIDER = "chroma";
CHROMA_HOST = cfg.vectorStore.config.host or "localhost";
CHROMA_PORT = toString (cfg.vectorStore.config.port or 8000);
CHROMA_COLLECTION = cfg.vectorStore.config.collection_name or "mem0_memories";
}
else {};
# Start script that sets up environment and runs the server
startScript = pkgs.writeShellScript "mem0-start" ''
set -e
# Load environment file if specified
${optionalString (cfg.environmentFile != null) ''
if [ -f "${cfg.environmentFile}" ]; then
set -a
source "${cfg.environmentFile}"
set +a
fi
''}
# Load API key from file if specified
${optionalString (cfg.llm.apiKeyFile != null) ''
if [ -f "${cfg.llm.apiKeyFile}" ]; then
export OPENAI_API_KEY="$(cat ${cfg.llm.apiKeyFile})"
fi
''}
# Create state directory
mkdir -p ${cfg.stateDir}
cd ${cfg.stateDir}
# Run the server
exec ${pythonEnv}/bin/mem0-server
'';
in {
options.m3ta.mem0 = {
enable = mkEnableOption "Mem0 REST API server";
package = mkOption {
type = types.package;
default = pkgs.mem0;
defaultText = literalExpression "pkgs.mem0";
description = "The mem0 package to use.";
};
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Host address to bind the server to.";
};
port = mkOption {
type = types.port;
default = 8000;
description = "Port to run the REST API server on.";
};
workers = mkOption {
type = types.int;
default = 1;
description = "Number of worker processes.";
};
logLevel = mkOption {
type = types.enum ["critical" "error" "warning" "info" "debug" "trace"];
default = "info";
description = "Logging level for the server.";
};
stateDir = mkOption {
type = types.path;
default = "/var/lib/mem0";
description = "Directory to store mem0 data and state.";
};
user = mkOption {
type = types.str;
default = "mem0";
description = "User account under which mem0 runs.";
};
group = mkOption {
type = types.str;
default = "mem0";
description = "Group under which mem0 runs.";
};
environmentFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Environment file containing additional configuration.
This file should contain KEY=value pairs, one per line.
Useful for secrets that shouldn't be in the Nix store.
'';
example = "/etc/mem0/environment";
};
# LLM Configuration
llm = {
provider = mkOption {
type = types.enum ["openai" "anthropic" "azure" "groq" "together" "ollama" "litellm"];
default = "openai";
description = "LLM provider to use for memory operations.";
};
model = mkOption {
type = types.str;
default = "gpt-4o-mini";
description = "Model name to use for the LLM.";
};
apiKeyFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Path to file containing the API key for the LLM provider.
The file should contain only the API key.
This is more secure than putting the key in the Nix store.
'';
example = "/run/secrets/openai-api-key";
};
temperature = mkOption {
type = types.nullOr types.float;
default = null;
description = "Temperature parameter for LLM generation.";
};
maxTokens = mkOption {
type = types.nullOr types.int;
default = null;
description = "Maximum tokens for LLM generation.";
};
extraConfig = mkOption {
type = types.attrs;
default = {};
description = "Additional LLM configuration options.";
example = {
top_p = 1.0;
frequency_penalty = 0.0;
};
};
};
# Vector Store Configuration
vectorStore = {
provider = mkOption {
type = types.enum [
"qdrant"
"chroma"
"pinecone"
"weaviate"
"faiss"
"pgvector"
"redis"
"elasticsearch"
"milvus"
];
default = "qdrant";
description = "Vector database provider to use.";
};
config = mkOption {
type = types.attrs;
default = {};
description = ''
Configuration for the vector store.
The structure depends on the provider.
'';
example = literalExpression ''
{
host = "localhost";
port = 6333;
collection_name = "mem0_memories";
}
'';
};
};
# Embedder Configuration
embedder = {
provider = mkOption {
type = types.nullOr (types.enum ["openai" "huggingface" "ollama" "vertexai"]);
default = null;
description = "Embedding model provider. If null, uses default.";
};
model = mkOption {
type = types.nullOr types.str;
default = null;
description = "Embedding model name to use.";
example = "text-embedding-3-small";
};
config = mkOption {
type = types.attrs;
default = {};
description = "Configuration for the embedder.";
example = {
model = "text-embedding-3-small";
};
};
};
};
config = mkIf cfg.enable {
# Create user and group
users.users.${cfg.user} = {
isSystemUser = true;
group = cfg.group;
description = "Mem0 service user";
home = cfg.stateDir;
createHome = true;
};
users.groups.${cfg.group} = {};
# Systemd service
systemd.services.mem0 = {
description = "Mem0 REST API Server";
after = ["network.target"];
wantedBy = ["multi-user.target"];
serviceConfig = {
Type = "simple";
User = cfg.user;
Group = cfg.group;
ExecStart = startScript;
Restart = "on-failure";
RestartSec = "5s";
# Security hardening
NoNewPrivileges = true;
PrivateTmp = true;
ProtectSystem = "strict";
ProtectHome = true;
ReadWritePaths = [cfg.stateDir];
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictRealtime = true;
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = false; # Python needs this
RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
};
environment =
{
PYTHONUNBUFFERED = "1";
MEM0_HOST = cfg.host;
MEM0_PORT = toString cfg.port;
MEM0_LLM_PROVIDER = cfg.llm.provider;
MEM0_LLM_MODEL = cfg.llm.model;
MEM0_HISTORY_DB_PATH = "${cfg.stateDir}/history.db";
MEM0_WORKERS = toString cfg.workers;
MEM0_LOG_LEVEL = cfg.logLevel;
}
// optionalAttrs (cfg.llm.temperature != null) {
MEM0_LLM_TEMPERATURE = toString cfg.llm.temperature;
}
// optionalAttrs (cfg.llm.extraConfig != {}) {
MEM0_LLM_EXTRA_CONFIG = builtins.toJSON cfg.llm.extraConfig;
}
// optionalAttrs (cfg.embedder.provider != null) {
MEM0_EMBEDDER_PROVIDER = cfg.embedder.provider;
}
// optionalAttrs (cfg.embedder.model != null) {
MEM0_EMBEDDER_MODEL = cfg.embedder.model;
}
// vectorStoreEnv;
};
# Open firewall port if binding to non-localhost
networking.firewall.allowedTCPPorts = mkIf (cfg.host != "127.0.0.1" && cfg.host != "localhost") [cfg.port];
};
}
+124
View File
@@ -0,0 +1,124 @@
# NixOS Module for Port Management
#
# This module provides centralized port management across your NixOS systems.
# Define ports once and use them consistently across all services, with
# support for host-specific overrides.
#
# Usage in your NixOS configuration:
#
# # In your flake.nix or configuration.nix:
# imports = [ inputs.m3ta-nixpkgs.nixosModules.default ];
#
# m3ta.ports = {
# enable = true;
#
# # Define your default ports
# definitions = {
# nginx = 80;
# grafana = 3000;
# prometheus = 9090;
# homepage = 8080;
# ssh = 22;
# };
#
# # Define host-specific overrides
# hostOverrides = {
# laptop = {
# nginx = 8080; # Use non-privileged port on laptop
# ssh = 2222;
# };
# server = {
# homepage = 3001;
# };
# };
#
# # Optionally set the current hostname for automatic port resolution
# currentHost = config.networking.hostName;
# };
#
# # Use ports in your configuration:
# services.nginx.defaultHTTPListenPort = config.m3ta.ports.get "nginx";
# services.grafana.settings.server.http_port = config.m3ta.ports.get "grafana";
#
# # Or access all ports for the current host:
# environment.etc."my-ports.json".text = builtins.toJSON config.m3ta.ports.all;
{
config,
lib,
...
}:
with lib; let
cfg = config.m3ta.ports;
portsLib = import ../../lib/ports.nix {inherit lib;};
portHelpers =
if cfg.enable
then
portsLib.mkPortHelpers {
ports = cfg.definitions;
hostPorts = cfg.hostOverrides;
}
else null;
in {
options.m3ta.ports = {
enable = mkEnableOption "centralized port management";
definitions = mkOption {
type = types.attrsOf types.port;
default = {};
description = "Default port definitions for services.";
};
hostOverrides = mkOption {
type = types.attrsOf (types.attrsOf types.port);
default = {};
description = "Host-specific port overrides.";
};
currentHost = mkOption {
type = types.str;
default = config.networking.hostName;
description = "Hostname to use for port resolution.";
};
# Internal computed options
get = mkOption {
type = types.raw;
readOnly = true;
internal = true;
};
getForHost = mkOption {
type = types.raw;
readOnly = true;
internal = true;
};
all = mkOption {
type = types.attrsOf types.port;
readOnly = true;
internal = true;
};
allForHost = mkOption {
type = types.raw;
readOnly = true;
internal = true;
};
services = mkOption {
type = types.listOf types.str;
readOnly = true;
internal = true;
};
};
config = mkIf cfg.enable {
m3ta.ports.get = service: portHelpers.getPort service cfg.currentHost;
m3ta.ports.getForHost = host: service: portHelpers.getPort service host;
m3ta.ports.all = portHelpers.getHostPorts cfg.currentHost;
m3ta.ports.allForHost = portHelpers.getHostPorts;
m3ta.ports.services = portHelpers.listServices;
};
}
+16
View File
@@ -0,0 +1,16 @@
{inputs, ...}: let
# Package modifications for upstream nixpkgs packages.
modifications = final: prev: {
n8n = import ./mods/n8n.nix {inherit prev;};
};
in {
# Default overlay: adds all custom packages and applies package modifications.
default = final: prev:
import ../pkgs {
pkgs = final;
inherit inputs;
}
// (modifications final prev);
inherit modifications;
}
+47
View File
@@ -0,0 +1,47 @@
{prev}: let
xlsxTarball = "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz";
xlsxIntegrity = "sha512-+nKZ39+nvK7Qq6i0PvWWRA4j/EkfWOtkP/YhMtupm+lJIiHxUrgTr1CcKv1nBk1rHtkRRQ3O2+Ih/q/sA+FXZA==";
patchXlsxLockfile = ''
substituteInPlace pnpm-lock.yaml \
--replace-fail \
"resolution: {tarball: ${xlsxTarball}}" \
"resolution: {integrity: ${xlsxIntegrity}, tarball: ${xlsxTarball}}"
'';
in
prev.n8n.overrideAttrs (finalAttrs: previousAttrs: {
version = "2.31.6";
src = prev.fetchFromGitHub {
owner = "n8n-io";
repo = "n8n";
tag = "n8n@${finalAttrs.version}";
hash = "sha256-OTVfIHnGTaBogEd93Ak2Pu3Jh7VweQNYbUeahq1Z/64=";
};
pnpmDeps = prev.fetchPnpmDeps {
inherit (finalAttrs) pname version src;
pnpm = prev.pnpm_10;
fetcherVersion = 3;
prePnpmInstall = patchXlsxLockfile;
hash = "sha256-Q3HCJg1KjdRJnPZJEUKcaCrh8tBhT9B3gqMz8xbBZVg=";
};
prePnpmInstall = (previousAttrs.prePnpmInstall or "") + patchXlsxLockfile;
preBuild =
(previousAttrs.preBuild or "")
+ ''
if [ ! -e node_modules/sass-embedded ] && [ -e node_modules/.pnpm/node_modules/sass-embedded ]; then
ln -s .pnpm/node_modules/sass-embedded node_modules/sass-embedded
fi
if [ ! -e node_modules/sqlite3 ] && [ -e node_modules/.pnpm/node_modules/sqlite3 ]; then
ln -s .pnpm/node_modules/sqlite3 node_modules/sqlite3
fi
'';
meta =
previousAttrs.meta
// {
changelog = "https://github.com/n8n-io/n8n/releases/tag/n8n@${finalAttrs.version}";
};
})
+33
View File
@@ -0,0 +1,33 @@
# pkgs/ AGENTS.md
## OVERVIEW
Custom package registry using `callPackage` pattern for flake-wide availability.
## STRUCTURE
- `default.nix`: Central registry (entry point for overlays)
- `code2prompt/`: Rust package
- `hyprpaper-random/`: Bash script
- `launch-webapp/`: Webapp wrapper
- `mem0/`: Python package + custom `server.py`
- `msty-studio/`: AppImage wrapper
- `pomodoro-timer/`: Timer utility
- `tuxedo-backlight/`: Hardware control
- `zellij-ps/`: Gitea-hosted package
## WHERE TO LOOK
- **Register new pkg**: Add entry to `pkgs/default.nix` attribute set
- **Modify pkg**: Edit `pkgs/<name>/default.nix` (version, hash, deps)
- **Check visibility**: `nix flake show` (uses `pkgs/default.nix` via `overlays/default.nix`)
- **Add scripts**: Place alongside `default.nix` in package folder (e.g., `mem0/server.py`)
## CONVENTIONS
- **CallPackage**: Always use `pkgs.callPackage ./dir {}` in registry
- **Dir == Attr**: Package directory name MUST match its registry attribute
- **Path literals**: Reference local assets using `./file` within derivations
- **Self-contained**: Keep all package-specific files in their own directory
## ANTI-PATTERNS
- **Orphaned dirs**: Creating `pkgs/new-pkg/` without updating `pkgs/default.nix`
- **Direct flake imports**: Importing packages in `flake.nix` instead of through the registry
- **Implicit deps**: Not declaring dependencies in the package function arguments
- **Non-derivations**: Placing NixOS/HM modules here (use `modules/` instead)
+130
View File
@@ -0,0 +1,130 @@
# crunch
Voice-notified reminders and AI crunch jobs via systemd transient timers. Schedules tasks that fire through `talk` (ElevenLabs TTS) — no NixOS rebuild needed, survives reboots.
## Usage
### Simple voice reminders
```bash
crunch at "14:30" "Müll rausbringen"
crunch at "2026-07-03 10:00" "Zahnarzttermin"
crunch in "30m" "Build checken"
crunch daily "09:00" "Daily standup"
crunch weekly "Mon 09:00" "Weekly review"
crunch weekly "Montag 09:00" "Weekly review" # German day names
```
### AI crunch jobs
Runs a prompt through `pi` or `opencode` in print mode, pipes result to `talk`:
```bash
crunch ai pi in "1h" "Fasse die neuesten Commits zusammen"
crunch ai opencode daily "08:00" "Review offene Issues und gib 3 Key-Points"
crunch ai pi weekly "Mon 09:00" "Generiere Weekly Summary aus git log"
```
### Custom script jobs
Runs any shell script on schedule. Script stdout → `talk`:
```bash
crunch script daily "08:00" ~/scripts/basecamp-daily.sh
crunch script in "2h" ~/scripts/deploy-check.sh -- --verbose
crunch script weekly "Mon 09:00" ~/scripts/weekly-report.sh
```
Example script:
```bash
#!/usr/bin/env bash
# ~/scripts/basecamp-daily.sh
TODOS=$(basecamp todos --today 2>/dev/null) || exit 0
echo "$TODOS" | pi -p "Erstelle Summary als ~/reports/daily.md. Antworte mit Top 3."
```
### Management
```bash
crunch list # List active jobs
crunch cancel crunch-mll-rausbringen-12345 # Cancel a job
crunch purge # Remove fired one-shot jobs
```
## Command Reference
```
crunch at <time> <message> One-shot (14:30 or "2026-07-03 14:30")
crunch in <duration> <message> One-shot after delay (30m, 2h, 1h30m)
crunch daily <time> <message> Recurring daily
crunch weekly <day> <time> <message> Recurring weekly (Mon/Montag)
crunch ai <engine> <type> <time> <prompt> AI crunch (pi|opencode)
crunch script <type> <time> <script.sh> [args] Custom script → talk
crunch list List active jobs
crunch cancel <name> Cancel a job
crunch purge Remove fired one-shot jobs
```
## Day Names
Supports English and German:
| English | German | systemd |
|---|---|---|
| Mon, Monday | Mo, Montag | Mon |
| Tue, Tuesday | Di, Dienstag | Tue |
| Wed, Wednesday | Mi, Mittwoch | Wed |
| Thu, Thursday | Do, Donnerstag | Thu |
| Fri, Friday | Fr, Freitag | Fri |
| Sat, Saturday | Sa, Samstag | Sat |
| Sun, Sunday | So, Sonntag | Sun |
## Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
| `ELEVENLABS_API_KEY` | ✅ | — | Required by `talk` |
| `VOICE_NOTIFY` | ❌ | `1` | `0` silences talk globally |
| `TALK` | ❌ | `talk` | Override path to talk binary |
## How It Works
```
┌─────────────────────────────────────────────┐
│ systemd --user transient timer fires │
│ │
│ crunch _say "message" │
│ └─ talk "message" (TTS via ElevenLabs) │
│ │
│ crunch _ai pi "prompt" │
│ └─ pi -p "prompt" | talk (AI → TTS) │
│ │
│ crunch _script ~/script.sh │
│ └─ bash ~/script.sh | talk (pipe → TTS)│
└─────────────────────────────────────────────┘
```
Uses `systemd-run --user` to create transient `.timer` + `.service` units. No NixOS rebuild needed — jobs are created and managed at runtime.
## Prerequisites
- `talk` package installed and in PATH
- `pi` and/or `opencode` for AI crunch mode
- `loginctl enable-linger <username>`**critical** for timers to fire when logged out
- `ELEVENLABS_API_KEY` in environment (or agenix secrets)
## NixOS Installation
```nix
# home-manager
home.packages = [ pkgs.m3ta.crunch pkgs.m3ta.talk ];
```
Verify lingering is enabled:
```bash
loginctl show-user $(whoami) | grep Linger=yes
# If not:
sudo loginctl enable-linger $(whoami)
```
+289
View File
@@ -0,0 +1,289 @@
{
lib,
stdenv,
writeShellScriptBin,
coreutils,
bash,
}: let
script = writeShellScriptBin "crunch" ''
#!/usr/bin/env bash
set -euo pipefail
# ═══════════════════════════════════════════════════════════════
# crunch — Voice-notified reminders & AI crunch jobs
# via systemd transient timers.
#
# Requires: talk (ElevenLabs TTS) in PATH, ELEVENLABS_API_KEY env.
# Optional: pi, opencode for AI crunch mode.
# ═══════════════════════════════════════════════════════════════
TALK="''${TALK:-talk}"
SELF="$(readlink -f "''${BASH_SOURCE[0]:-$0}")"
# ── Helpers ───────────────────────────────────────────────────
usage() {
cat <<'EOF'
crunch voice-notified reminders and AI jobs via systemd timers
Usage:
crunch at <time> <message> One-shot (14:30 or "2026-07-03 14:30")
crunch in <duration> <message> One-shot after delay (30m, 2h, 1h30m)
crunch daily <time> <message> Recurring daily at time
crunch weekly <day> <time> <message> Recurring weekly (Mon or Montag)
crunch ai <engine> <type> <time> <prompt> AI crunch (pi|opencode)
crunch script <type> <time> <script.sh> [args] Custom script talk
crunch list List active jobs
crunch cancel <name> Cancel a job
crunch purge Remove fired one-shot jobs
Examples:
crunch at "14:30" "Müll rausbringen"
crunch at "2026-07-03 10:00" "Zahnarzttermin"
crunch in "30m" "Build checken"
crunch daily "09:00" "Daily standup"
crunch weekly "Mon 09:00" "Weekly review"
crunch weekly "Montag 09:00" "Weekly review"
crunch ai pi in "1h" "Fasse neueste Commits zusammen"
crunch ai opencode daily "08:00" "Review offene Issues"
crunch script daily "08:00" ~/scripts/basecamp-daily.sh
crunch list
crunch cancel mll-rausbringen-12345
Environment:
VOICE_NOTIFY=0 Silence voice output (passed to talk)
ELEVENLABS_API_KEY Required by talk
TALK Override path to talk binary
EOF
}
# German → systemd day abbreviations
norm_day() {
local d="''${1,,}"
d="''${d%%.*}" # strip trailing dot (German abbreviation)
case "$d" in
mo|mon|monday|montag) echo "Mon" ;;
di|tue|tues|tuesday|dienstag) echo "Tue" ;;
mi|wed|weds|wednesday|mittwoch) echo "Wed" ;;
do|thu|thur|thurs|thursday|donnerstag) echo "Thu" ;;
fr|fri|friday|freitag) echo "Fri" ;;
sa|sat|saturday|samstag) echo "Sat" ;;
so|su|sun|sunday|sonntag) echo "Sun" ;;
*) echo "''${1^}" ;;
esac
}
make_name() {
local msg="''${1:?No message}"
local slug
slug="''${msg,,}"
slug="''${slug//[^a-z0-9 ]/}"
slug="''${slug// /-}"
slug="''${slug:0:25}"
slug="''${slug%-}" # trim trailing dash
echo "crunch-''${slug:-job}-$RANDOM"
}
# schedule <type> <time_spec> <exec_cmd> <name>
schedule() {
local type="$1" time_spec="$2" exec_cmd="$3" name="$4"
local timer_flag=""
case "$type" in
at)
if [[ "$time_spec" == *' '* ]]; then
# "2026-07-03 14:30" → specific date
timer_flag="--on-calendar=''${time_spec}:00"
else
# "14:30" → next matching time
timer_flag="--on-calendar=*-*-* ''${time_spec}:00"
fi
;;
in)
timer_flag="--on-active=''${time_spec}"
;;
daily)
timer_flag="--on-calendar=*-*-* ''${time_spec}:00"
;;
weekly)
local day time_part
day="$(norm_day "''${time_spec%% *}")"
time_part="''${time_spec##* }"
timer_flag="--on-calendar=''${day} *-*-* ''${time_part}:00"
;;
*)
echo "Unknown schedule type: $type" >&2
exit 1
;;
esac
systemd-run --user \
--unit="''${name}" \
--description="crunch job" \
"''${timer_flag}" \
bash -lc "''${exec_cmd}" \
&& echo " Scheduled: $name"
}
# ── Internal execution (called by systemd) ────────────────────
case "''${1:-}" in
_say)
shift
exec "$TALK" "$*"
;;
_ai)
engine="$2"; shift 2
case "$engine" in
pi|pi-agent)
pi -p "$*" | "$TALK"
;;
opencode|oc)
opencode run "$*" -q | "$TALK"
;;
*)
echo "Unknown engine: $engine (use: pi, opencode)" >&2
exit 1
;;
esac
exit $?
;;
_script)
script_path="$2"; shift 2
rc=0
output=$(bash "$script_path" "$@" 2>&1) || rc=$?
if [ -n "''${output:-}" ]; then
printf '%s' "$output" | "$TALK"
fi
exit "$rc"
;;
esac
# ── CLI ───────────────────────────────────────────────────────
[ $# -lt 1 ] && { usage; exit 0; }
cmd="$1"; shift
case "$cmd" in
# ── Simple voice reminders ──
at)
[ $# -lt 2 ] && { echo "Usage: crunch at <time> <message>" >&2; exit 1; }
time_spec="$1"; shift
msg="$*"
name="$(make_name "$msg")"
schedule at "$time_spec" "$SELF _say $(printf '%q' "$msg")" "$name"
;;
in)
[ $# -lt 2 ] && { echo "Usage: crunch in <duration> <message>" >&2; exit 1; }
duration="$1"; shift
msg="$*"
name="$(make_name "$msg")"
schedule in "$duration" "$SELF _say $(printf '%q' "$msg")" "$name"
;;
daily)
[ $# -lt 2 ] && { echo "Usage: crunch daily <time> <message>" >&2; exit 1; }
time_spec="$1"; shift
msg="$*"
name="$(make_name "$msg")"
schedule daily "$time_spec" "$SELF _say $(printf '%q' "$msg")" "$name"
;;
weekly)
[ $# -lt 2 ] && { echo "Usage: crunch weekly <day> <time> <message>" >&2; exit 1; }
day_time="$1"; shift
msg="$*"
name="$(make_name "$msg")"
schedule weekly "$day_time" "$SELF _say $(printf '%q' "$msg")" "$name"
;;
# ── AI crunch jobs ──
ai)
[ $# -lt 4 ] && { echo "Usage: crunch ai <pi|opencode> <at|in|daily|weekly> <time> <prompt>" >&2; exit 1; }
engine="$1"; sub_type="$2"; time_spec="$3"; shift 3
prompt="$*"
name="$(make_name "$prompt")"
schedule "$sub_type" "$time_spec" \
"$SELF _ai $engine $(printf '%q' "$prompt")" "$name"
;;
# ── Custom script crunch jobs ──
script)
[ $# -lt 3 ] && { echo "Usage: crunch script <at|in|daily|weekly> <time> <script.sh> [args...]" >&2; exit 1; }
sub_type="$1"; time_spec="$2"; script_path="$3"; shift 3
script_path="$(readlink -f "$script_path")"
[ ! -f "$script_path" ] && { echo "Script not found: $script_path" >&2; exit 1; }
name="$(make_name "$(basename "$script_path" .sh)")"
exec_cmd="$SELF _script $(printf '%q' "$script_path")"
if [ $# -gt 0 ]; then
exec_cmd+=" $(printf '%q ' "$@")"
fi
schedule "$sub_type" "$time_spec" "$exec_cmd" "$name"
;;
# ── Management ──
list)
echo "Active crunch jobs:"
echo ""
systemctl --user list-timers 'crunch-*' --no-pager 2>/dev/null \
| grep -E 'crunch-|^NEXT|^NEXT|^$' || echo " (none)"
;;
cancel)
[ $# -lt 1 ] && { echo "Usage: crunch cancel <name>" >&2; exit 1; }
name="$1"
# Accept with or without crunch- prefix
[[ "$name" != crunch-* ]] && name="crunch-$name"
systemctl --user stop "''${name}.timer" "''${name}.service" 2>/dev/null \
&& echo " Cancelled: $name" \
|| echo " Not found: $name"
;;
purge)
echo "Purging fired one-shot jobs..."
local purged=0
for unit in $(systemctl --user list-units 'crunch-*' --all --plain --no-legend --no-pager 2>/dev/null | awk '{print $1}'); do
if systemctl --user is-failed "$unit" &>/dev/null; then
systemctl --user stop "$unit" 2>/dev/null || true
systemctl --user reset-failed "$unit" 2>/dev/null || true
echo " Purged: $unit"
purged=$((purged + 1))
fi
done
echo " Purged $purged unit(s)"
;;
-h|--help|help)
usage
;;
*)
echo "Unknown command: $cmd" >&2
echo ""
usage
exit 1
;;
esac
'';
in
stdenv.mkDerivation {
pname = "crunch";
version = "0.1.0";
dontUnpack = true;
installPhase = ''
mkdir -p "$out/bin"
ln -s ${script}/bin/crunch "$out/bin/crunch"
'';
meta = with lib; {
description = "Voice-notified reminders and AI crunch jobs via systemd transient timers";
homepage = "https://code.m3ta.dev/m3tam3re/nixpkgs";
license = licenses.mit;
platforms = platforms.linux;
mainProgram = "crunch";
};
}
+43
View File
@@ -0,0 +1,43 @@
# m3ta-nixpkgs package registry
#
# Flake inputs used:
# inputs.basecamp → basecamp (pass-through)
# inputs.openspec → openspec (pass-through)
# inputs.opencode → opencode-desktop (build inputs + patches)
# inputs.agents → not used directly here (used by lib/)
{
pkgs,
inputs,
...
}: let
system = pkgs.stdenv.hostPlatform.system;
in {
# ── Local packages ────────────────────────────────────────────────
# Standard packages built from source in ./<name>/default.nix.
# No flake inputs required.
sidecar = pkgs.callPackage ./sidecar {};
td = pkgs.callPackage ./td {};
eigent = pkgs.callPackage ./eigent {};
hyprpaper-random = pkgs.callPackage ./hyprpaper-random {};
launch-webapp = pkgs.callPackage ./launch-webapp {};
mem0 = pkgs.callPackage ./mem0 {};
msty-studio = pkgs.callPackage ./msty-studio {};
pomodoro-timer = pkgs.callPackage ./pomodoro-timer {};
rofi-project-opener = pkgs.callPackage ./rofi-project-opener {};
stt-ptt = pkgs.callPackage ./stt-ptt {};
tuxedo-backlight = pkgs.callPackage ./tuxedo-backlight {};
kestractl = pkgs.callPackage ./kestractl {};
openshell = pkgs.callPackage ./openshell {};
openwork = pkgs.callPackage ./openwork {};
zellij-ps = pkgs.callPackage ./zellij-ps {};
vibetyper = pkgs.callPackage ./vibetyper {};
talk = pkgs.callPackage ./talk {};
crunch = pkgs.callPackage ./crunch {};
# ── Pass-through packages ──────────────────────────────────────────
# Imported directly from flake inputs. No local modifications.
basecamp = inputs.basecamp.packages.${system}.default;
openspec = inputs.openspec.packages.${system}.default;
}
+72
View File
@@ -0,0 +1,72 @@
{
lib,
stdenv,
writeShellScriptBin,
fd,
hyprland,
coreutils,
gawk,
}: let
script = writeShellScriptBin "hyprpaper-random" ''
#!/usr/bin/env bash
set -euo pipefail
# Directory (override with WALLPAPER_DIR)
DIR="''${WALLPAPER_DIR:-''${XDG_CONFIG_HOME:-$HOME/.config}/hypr/wallpapers}"
HYPRCTL="${hyprland}/bin/hyprctl"
FD="${fd}/bin/fd"
SHUF="${coreutils}/bin/shuf"
TR="${coreutils}/bin/tr"
AWK="${gawk}/bin/awk"
# Pick one random image (null-safe)
WALLPAPER="$(
"$FD" . "$DIR" -t f -e jpg -e jpeg -e png -e webp -e avif -0 --follow --hidden \
| "$SHUF" -z -n1 \
| "$TR" -d '\0'
)"
if [[ -z "''${WALLPAPER:-}" ]]; then
echo "No wallpapers found in: $DIR" >&2
exit 1
fi
# Preload so hyprpaper can use it
"$HYPRCTL" hyprpaper preload "$WALLPAPER" >/dev/null 2>&1 || true
# Apply to all monitors
"$HYPRCTL" monitors \
| "$AWK" '/^Monitor /{print $2}' \
| while IFS= read -r mon; do
[ -n "$mon" ] && "$HYPRCTL" hyprpaper wallpaper "$mon,$WALLPAPER"
done
exit 0
'';
in
stdenv.mkDerivation {
pname = "hyprpaper-random";
version = "0.1.1";
dontUnpack = true;
buildInputs = [
fd
hyprland
coreutils
gawk
];
installPhase = ''
mkdir -p "$out/bin"
ln -s ${script}/bin/hyprpaper-random "$out/bin/hyprpaper-random"
'';
meta = {
description = "Minimal random wallpaper setter for Hyprpaper";
license = lib.licenses.mit;
platforms = lib.platforms.linux;
mainProgram = "hyprpaper-random";
};
}
+37
View File
@@ -0,0 +1,37 @@
{
lib,
stdenv,
fetchurl,
autoPatchelfHook,
}: let
sources = lib.importJSON ./sources.json;
source = sources.sources.${stdenv.hostPlatform.system};
in
stdenv.mkDerivation {
pname = "kestractl";
version = sources.version;
src = fetchurl {
inherit (source) url hash;
};
nativeBuildInputs = [autoPatchelfHook];
unpackPhase = ''
tar -xzf $src
'';
installPhase = ''
install -Dm755 kestractl $out/bin/kestractl
'';
passthru.updateScript = ./update.sh;
meta = with lib; {
description = "CLI for the Kestra workflow orchestration platform";
homepage = "https://github.com/kestra-io/kestractl";
license = licenses.asl20;
platforms = attrNames sources.sources;
mainProgram = "kestractl";
};
}
+13
View File
@@ -0,0 +1,13 @@
{
"version": "1.15.0",
"sources": {
"aarch64-linux": {
"url": "https://github.com/kestra-io/kestractl/releases/download/1.15.0/kestractl_1.15.0_linux_arm64.tar.gz",
"hash": "sha256-iBkhetgGy/8Nljxb0yO8hjln8LYgTHTOPdNsee1W/U4="
},
"x86_64-linux": {
"url": "https://github.com/kestra-io/kestractl/releases/download/1.15.0/kestractl_1.15.0_linux_amd64.tar.gz",
"hash": "sha256-hvQsOIODwDPZEW4wyZhd5Sb70tQsfwU4ZrHrxYK3VKc="
}
}
}
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env nix-shell
#!nix-shell --pure -i bash -p bash curl jq nix cacert git
set -euo pipefail
# Update kestractl sources.json with the latest release from GitHub.
# Usage: ./update.sh (or via nix-update --update-script)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SOURCES_FILE="$SCRIPT_DIR/sources.json"
# Map Nix system -> GitHub release asset name fragment
declare -A SYSTEMS=(
["x86_64-linux"]="linux_amd64"
["aarch64-linux"]="linux_arm64"
)
echo "Fetching latest kestractl release..."
LATEST=$(curl -fsSL "https://api.github.com/repos/kestra-io/kestractl/releases/latest")
VERSION=$(echo "$LATEST" | jq -r '.tag_name')
echo "Latest version: $VERSION"
CURRENT_VERSION=$(jq -r '.version' "$SOURCES_FILE")
if [[ "$VERSION" == "$CURRENT_VERSION" ]]; then
echo "Already at latest version $VERSION, nothing to do."
exit 0
fi
NEW_SOURCES="{}"
for NIX_SYSTEM in "${!SYSTEMS[@]}"; do
ASSET_FRAG="${SYSTEMS[$NIX_SYSTEM]}"
URL="https://github.com/kestra-io/kestractl/releases/download/${VERSION}/kestractl_${VERSION}_${ASSET_FRAG}.tar.gz"
echo "Fetching hash for $NIX_SYSTEM ($URL)..."
HASH=$(nix-prefetch-url --type sha256 "$URL" 2>/dev/null)
SRI=$(nix hash to-sri --type sha256 "$HASH")
NEW_SOURCES=$(echo "$NEW_SOURCES" | jq \
--arg sys "$NIX_SYSTEM" \
--arg url "$URL" \
--arg hash "$SRI" \
'. + {($sys): {url: $url, hash: $hash}}')
done
jq -n \
--arg version "$VERSION" \
--argjson sources "$NEW_SOURCES" \
'{"version": $version, "sources": $sources}' \
> "$SOURCES_FILE"
echo "Updated $SOURCES_FILE to $VERSION"
# Commit when running in CI or via nix-update
if [[ -d "$SCRIPT_DIR/../../.git" ]] || git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
NIXPKGS_ROOT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || true)
if [[ -n "$NIXPKGS_ROOT" && -n "$(git -C "$NIXPKGS_ROOT" status --porcelain "$SOURCES_FILE")" ]]; then
git -C "$NIXPKGS_ROOT" add "$SOURCES_FILE"
git -C "$NIXPKGS_ROOT" commit -m "kestractl: ${CURRENT_VERSION} -> ${VERSION}"
echo "Committed update to git"
fi
fi
+41
View File
@@ -0,0 +1,41 @@
{
lib,
stdenv,
writeShellScriptBin,
}: let
launcher = writeShellScriptBin "launch-webapp" ''
#!/usr/bin/env bash
browser=$(xdg-settings get default-web-browser)
case "$browser" in
google-chrome*) browser_bin="google-chrome" ;;
brave-browser*) browser_bin="brave-browser" ;;
microsoft-edge*) browser_bin="microsoft-edge" ;;
opera*) browser_bin="opera" ;;
vivaldi*) browser_bin="vivaldi" ;;
*) browser_bin="chromium" ;;
esac
exec_cmd="/etc/profiles/per-user/$USER/bin/$browser_bin"
exec setsid uwsm app -- "$exec_cmd" --app="$1" ''${@:2}
'';
in
stdenv.mkDerivation {
pname = "launch-webapp";
version = "0.1.0";
dontUnpack = true;
installPhase = ''
mkdir -p $out/bin
ln -s ${launcher}/bin/launch-webapp $out/bin/launch-webapp
'';
meta = {
description = "Launches a web app using your default browser in app mode.";
license = lib.licenses.mit;
platforms = lib.platforms.linux;
mainProgram = "launch-webapp";
};
}
+102
View File
@@ -0,0 +1,102 @@
{
lib,
nix-update-script,
python3,
fetchFromGitHub,
}:
python3.pkgs.buildPythonPackage rec {
pname = "mem0ai";
version = "2.0.2";
pyproject = true;
src = fetchFromGitHub {
owner = "mem0ai";
repo = "mem0";
rev = "v${version}";
hash = "sha256-SV/+v0WmR6iZyyhPIXtj0PcIpPlSclak0zuSsIGebUo=";
};
# Relax Python dependency version constraints
# mem0 has strict version pins that may not match nixpkgs versions
pythonRelaxDeps = true;
build-system = with python3.pkgs; [
hatchling
];
dependencies = with python3.pkgs; [
litellm
qdrant-client
pydantic
openai
posthog
pytz
sqlalchemy
protobuf
uvicorn
fastapi
];
optional-dependencies = with python3.pkgs; {
graph = [
# Note: some graph dependencies may not be available in nixpkgs
# neo4j is available, others will need to be packaged separately
];
vector_stores = [
# chromadb # available in nixpkgs
# pinecone-client # may need packaging
# weaviate-client # may need packaging
# faiss # available as faiss-cpu
psycopg
pymongo
pymysql
redis
elasticsearch
];
llms = [
groq
openai
# together # may need packaging
# litellm # may need packaging
# ollama # may need packaging
# google-generativeai # may need packaging
];
extras = [
boto3
# langchain-community # may need packaging
# sentence-transformers # may need packaging
elasticsearch
# fastembed # may need packaging
];
};
# Skip tests for now since they require additional test dependencies
doCheck = false;
# Disable imports check because mem0 tries to create directories at import time
# which fails in the Nix sandbox (/homeless-shelter)
pythonImportsCheck = [];
postInstall = ''
install -Dm755 ${./server.py} $out/bin/mem0-server
'';
passthru.updateScript = nix-update-script {};
meta = with lib; {
description = "Long-term memory layer for AI agents with REST API support";
longDescription = ''
Mem0 provides a sophisticated memory layer for AI applications, offering:
- Memory management for AI agents (add, search, update, delete)
- REST API server for easy integration
- Support for multiple vector storage backends (Qdrant, Chroma, etc.)
- Graph memory capabilities
- Multi-modal support
- Configurable LLM and embedding models
'';
homepage = "https://github.com/mem0ai/mem0";
changelog = "https://github.com/mem0ai/mem0/releases/tag/v${version}";
license = licenses.asl20;
platforms = platforms.linux;
};
}
+301
View File
@@ -0,0 +1,301 @@
#!/usr/bin/env python3
"""
Mem0 REST API Server
A FastAPI-based REST server for mem0 memory operations.
"""
import logging
import os
import sys
from typing import Any, Dict, List, Optional
from fastapi import FastAPI, HTTPException
from fastapi.responses import JSONResponse, RedirectResponse
from pydantic import BaseModel, Field
from mem0 import Memory
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
# Configuration from environment variables
def get_config_from_env() -> Dict[str, Any]:
"""Build mem0 configuration from environment variables."""
config = {"version": "v1.1"}
# Vector store configuration
vector_provider = os.environ.get("MEM0_VECTOR_PROVIDER", "qdrant")
config["vector_store"] = {"provider": vector_provider}
if vector_provider == "qdrant":
config["vector_store"]["config"] = {
"host": os.environ.get("QDRANT_HOST", "localhost"),
"port": int(os.environ.get("QDRANT_PORT", "6333")),
"collection_name": os.environ.get("QDRANT_COLLECTION", "mem0_memories"),
}
elif vector_provider == "pgvector":
config["vector_store"]["config"] = {
"host": os.environ.get("POSTGRES_HOST", "localhost"),
"port": int(os.environ.get("POSTGRES_PORT", "5432")),
"dbname": os.environ.get("POSTGRES_DB", "postgres"),
"user": os.environ.get("POSTGRES_USER", "postgres"),
"password": os.environ.get("POSTGRES_PASSWORD", "postgres"),
"collection_name": os.environ.get("POSTGRES_COLLECTION", "mem0_memories"),
}
elif vector_provider == "chroma":
config["vector_store"]["config"] = {
"host": os.environ.get("CHROMA_HOST", "localhost"),
"port": int(os.environ.get("CHROMA_PORT", "8000")),
"collection_name": os.environ.get("CHROMA_COLLECTION", "mem0_memories"),
}
# LLM configuration
llm_provider = os.environ.get("MEM0_LLM_PROVIDER", "openai")
config["llm"] = {
"provider": llm_provider,
"config": {
"model": os.environ.get("MEM0_LLM_MODEL", "gpt-4o-mini"),
}
}
# Temperature: only include if set (null means use provider default)
temperature = os.environ.get("MEM0_LLM_TEMPERATURE")
if temperature is not None:
config["llm"]["config"]["temperature"] = float(temperature)
# Extra config: merge JSON env var if provided
extra_config_json = os.environ.get("MEM0_LLM_EXTRA_CONFIG")
if extra_config_json:
import json
try:
extra_config = json.loads(extra_config_json)
config["llm"]["config"].update(extra_config)
except json.JSONDecodeError:
logging.warning(f"Failed to parse MEM0_LLM_EXTRA_CONFIG: {extra_config_json}")
# Add API key if available
if llm_provider == "openai":
api_key = os.environ.get("OPENAI_API_KEY")
if api_key:
config["llm"]["config"]["api_key"] = api_key
# Embedder configuration
embedder_provider = os.environ.get("MEM0_EMBEDDER_PROVIDER", "openai")
config["embedder"] = {
"provider": embedder_provider,
}
# Embedder model: only include if provider is set
if embedder_provider:
embedder_config = {}
embedder_model = os.environ.get("MEM0_EMBEDDER_MODEL")
if embedder_model:
embedder_config["model"] = embedder_model
config["embedder"]["config"] = embedder_config
if embedder_provider == "openai":
api_key = os.environ.get("OPENAI_API_KEY")
if api_key:
config["embedder"]["config"]["api_key"] = api_key
# History DB path
history_db_path = os.environ.get("MEM0_HISTORY_DB_PATH", "/var/lib/mem0/history.db")
config["history_db_path"] = history_db_path
return config
# Initialize Memory instance
try:
config = get_config_from_env()
logging.info(f"Initializing mem0 with config: {config}")
# Validate API key is set for OpenAI provider
if config.get("llm", {}).get("provider") == "openai":
if not config.get("llm", {}).get("config", {}).get("api_key"):
logging.error("OPENAI_API_KEY environment variable is required but not set.")
logging.error("Please set OPENAI_API_KEY environment variable or configure apiKeyFile in NixOS module.")
sys.exit(1)
MEMORY_INSTANCE = Memory.from_config(config)
logging.info("Memory instance initialized successfully")
except Exception as e:
logging.error(f"Failed to initialize Memory: {e}")
logging.error("Please check your configuration and ensure all required services are running.")
sys.exit(1)
app = FastAPI(
title="Mem0 REST API",
description="A REST API for managing and searching memories for your AI Agents and Apps.",
version="1.0.0",
)
class Message(BaseModel):
role: str = Field(..., description="Role of the message (user or assistant).")
content: str = Field(..., description="Message content.")
class MemoryCreate(BaseModel):
messages: List[Message] = Field(..., description="List of messages to store.")
user_id: Optional[str] = None
agent_id: Optional[str] = None
run_id: Optional[str] = None
metadata: Optional[Dict[str, Any]] = None
class SearchRequest(BaseModel):
query: str = Field(..., description="Search query.")
user_id: Optional[str] = None
run_id: Optional[str] = None
agent_id: Optional[str] = None
filters: Optional[Dict[str, Any]] = None
@app.get("/", summary="Redirect to documentation", include_in_schema=False)
def home():
"""Redirect to the OpenAPI documentation."""
return RedirectResponse(url="/docs")
@app.get("/health", summary="Health check")
def health():
"""Check if the server is running."""
return {"status": "healthy", "service": "mem0-api"}
@app.post("/configure", summary="Configure Mem0")
def set_config(config: Dict[str, Any]):
"""Set memory configuration."""
global MEMORY_INSTANCE
MEMORY_INSTANCE = Memory.from_config(config)
return {"message": "Configuration set successfully"}
@app.post("/memories", summary="Create memories")
def add_memory(memory_create: MemoryCreate):
"""Store new memories."""
if not any([memory_create.user_id, memory_create.agent_id, memory_create.run_id]):
raise HTTPException(status_code=400, detail="At least one identifier (user_id, agent_id, run_id) is required.")
params = {k: v for k, v in memory_create.model_dump().items() if v is not None and k != "messages"}
try:
response = MEMORY_INSTANCE.add(messages=[m.model_dump() for m in memory_create.messages], **params)
return JSONResponse(content=response)
except Exception as e:
logging.exception("Error in add_memory:")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/memories", summary="Get memories")
def get_all_memories(
user_id: Optional[str] = None,
run_id: Optional[str] = None,
agent_id: Optional[str] = None,
):
"""Retrieve stored memories."""
if not any([user_id, run_id, agent_id]):
raise HTTPException(status_code=400, detail="At least one identifier is required.")
try:
params = {
k: v for k, v in {"user_id": user_id, "run_id": run_id, "agent_id": agent_id}.items() if v is not None
}
return MEMORY_INSTANCE.get_all(**params)
except Exception as e:
logging.exception("Error in get_all_memories:")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/memories/{memory_id}", summary="Get a memory")
def get_memory(memory_id: str):
"""Retrieve a specific memory by ID."""
try:
return MEMORY_INSTANCE.get(memory_id)
except Exception as e:
logging.exception("Error in get_memory:")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/search", summary="Search memories")
def search_memories(search_req: SearchRequest):
"""Search for memories based on a query."""
try:
params = {k: v for k, v in search_req.model_dump().items() if v is not None and k != "query"}
return MEMORY_INSTANCE.search(query=search_req.query, **params)
except Exception as e:
logging.exception("Error in search_memories:")
raise HTTPException(status_code=500, detail=str(e))
@app.put("/memories/{memory_id}", summary="Update a memory")
def update_memory(memory_id: str, updated_memory: Dict[str, Any]):
"""Update an existing memory with new content."""
try:
return MEMORY_INSTANCE.update(memory_id=memory_id, data=updated_memory)
except Exception as e:
logging.exception("Error in update_memory:")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/memories/{memory_id}/history", summary="Get memory history")
def memory_history(memory_id: str):
"""Retrieve memory history."""
try:
return MEMORY_INSTANCE.history(memory_id=memory_id)
except Exception as e:
logging.exception("Error in memory_history:")
raise HTTPException(status_code=500, detail=str(e))
@app.delete("/memories/{memory_id}", summary="Delete a memory")
def delete_memory(memory_id: str):
"""Delete a specific memory by ID."""
try:
MEMORY_INSTANCE.delete(memory_id=memory_id)
return {"message": "Memory deleted successfully"}
except Exception as e:
logging.exception("Error in delete_memory:")
raise HTTPException(status_code=500, detail=str(e))
@app.delete("/memories", summary="Delete all memories")
def delete_all_memories(
user_id: Optional[str] = None,
run_id: Optional[str] = None,
agent_id: Optional[str] = None,
):
"""Delete all memories for a given identifier."""
if not any([user_id, run_id, agent_id]):
raise HTTPException(status_code=400, detail="At least one identifier is required.")
try:
params = {
k: v for k, v in {"user_id": user_id, "run_id": run_id, "agent_id": agent_id}.items() if v is not None
}
MEMORY_INSTANCE.delete_all(**params)
return {"message": "All relevant memories deleted"}
except Exception as e:
logging.exception("Error in delete_all_memories:")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/reset", summary="Reset all memories")
def reset_memory():
"""Completely reset stored memories."""
try:
MEMORY_INSTANCE.reset()
return {"message": "All memories reset"}
except Exception as e:
logging.exception("Error in reset_memory:")
raise HTTPException(status_code=500, detail=str(e))
if __name__ == "__main__":
import uvicorn
host = os.environ.get("MEM0_HOST", "127.0.0.1")
port = int(os.environ.get("MEM0_PORT", "8000"))
workers = int(os.environ.get("MEM0_WORKERS", "1"))
log_level = os.environ.get("MEM0_LOG_LEVEL", "info")
uvicorn.run(app, host=host, port=port, workers=workers, log_level=log_level)
+43
View File
@@ -0,0 +1,43 @@
{
appimageTools,
fetchurl,
lib,
nodejs,
uv,
python3,
makeWrapper,
}: let
pname = "msty-studio";
version = "2.0.0-beta.4";
src = fetchurl {
url = "https://next-assets.msty.studio/app/alpha/linux/MstyStudio_x86_64.AppImage";
sha256 = "sha256-zJcGK7QEL3ROgVJy13mMdY/437H3Zx8EwSXy7rEhV9w=";
};
appimageContents = appimageTools.extractType2 {inherit pname version src;};
in
appimageTools.wrapType2 {
inherit pname version src;
nativeBuildInputs = [makeWrapper];
extraPkgs = pkgs: [
nodejs
uv
python3
];
extraInstallCommands = ''
install -m 444 -D ${appimageContents}/MstyStudio.desktop -t $out/share/applications
substituteInPlace $out/share/applications/MstyStudio.desktop \
--replace 'Exec=AppRun' 'Exec=${pname}'
install -m 444 -D ${appimageContents}/MstyStudio.png \
$out/share/icons/hicolor/256x256/apps/MstyStudio.png
wrapProgram $out/bin/${pname} \
--prefix PATH : ${nodejs}/bin:${uv}/bin:${python3}/bin
'';
meta = {
description = "Msty Studio enables advanced, privacypreserving AI workflows entirely on your local machine.";
license = lib.licenses.unfree;
platforms = lib.platforms.linux;
mainProgram = "msty-studio";
};
}
+35
View File
@@ -0,0 +1,35 @@
{
lib,
stdenv,
fetchurl,
}: let
sources = lib.importJSON ./sources.json;
source = sources.sources.${stdenv.hostPlatform.system};
in
stdenv.mkDerivation {
pname = "openshell";
version = lib.removePrefix "v" sources.version;
src = fetchurl {
inherit (source) url hash;
};
unpackPhase = ''
tar -xzf $src
'';
installPhase = ''
install -Dm755 openshell $out/bin/openshell
'';
passthru.updateScript = ./update.sh;
meta = with lib; {
description = "Safe, private runtime for autonomous AI agents";
homepage = "https://github.com/NVIDIA/OpenShell";
license = licenses.asl20;
platforms = attrNames sources.sources;
mainProgram = "openshell";
maintainers = [];
};
}
+17
View File
@@ -0,0 +1,17 @@
{
"version": "v0.0.62",
"sources": {
"aarch64-linux": {
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.62/openshell-aarch64-unknown-linux-musl.tar.gz",
"hash": "sha256-10jJ4pJ0lxXYI9ns/icicELZzDft4nUprxoQ9/s/8jU="
},
"x86_64-linux": {
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.62/openshell-x86_64-unknown-linux-musl.tar.gz",
"hash": "sha256-0E4RXPeNZJF9c3kW6B1xOA2y7nNPg0O+3dfXnugfDxY="
},
"aarch64-darwin": {
"url": "https://github.com/NVIDIA/OpenShell/releases/download/v0.0.62/openshell-aarch64-apple-darwin.tar.gz",
"hash": "sha256-BRkhA1EsFQApkt8Y8+XXgZK9tyBxZHz6m0Rn4td2XH8="
}
}
}

Some files were not shown because too many files have changed in this diff Show More