Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e89b961b0b |
BIN
Binary file not shown.
Binary file not shown.
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
# Use bd merge for beads JSONL files
|
|
||||||
.beads/issues.jsonl merge=beads
|
|
||||||
@@ -1,526 +0,0 @@
|
|||||||
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
|
|
||||||
-45
@@ -1,45 +0,0 @@
|
|||||||
# 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
|
|
||||||
Vendored
-7
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"success": true,
|
|
||||||
"clones": [],
|
|
||||||
"duplicatedLines": 0,
|
|
||||||
"totalLines": 0,
|
|
||||||
"percentage": 0
|
|
||||||
}
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"timestamp": "2026-04-15T09:30:34.459Z"
|
|
||||||
}
|
|
||||||
Vendored
-9
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"success": false,
|
|
||||||
"issues": [],
|
|
||||||
"unusedExports": [],
|
|
||||||
"unusedFiles": [],
|
|
||||||
"unusedDeps": [],
|
|
||||||
"unlistedDeps": [],
|
|
||||||
"summary": "Failed to parse output"
|
|
||||||
}
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"timestamp": "2026-04-15T09:30:35.667Z"
|
|
||||||
}
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
null
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"timestamp": "2026-04-15T09:28:51.987Z"
|
|
||||||
}
|
|
||||||
Vendored
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"items": []
|
|
||||||
}
|
|
||||||
-3
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"timestamp": "2026-04-15T09:28:16.965Z"
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"files": {},
|
|
||||||
"turnCycles": 0,
|
|
||||||
"maxCycles": 3,
|
|
||||||
"lastUpdated": "2026-04-15T09:30:35.668Z"
|
|
||||||
}
|
|
||||||
@@ -1,225 +0,0 @@
|
|||||||
# m3ta-nixpkgs Knowledge Base
|
|
||||||
|
|
||||||
## MANDATORY: Use td for Task Management
|
|
||||||
|
|
||||||
You must run td usage --new-session at conversation start (or after /clear) to see current work.
|
|
||||||
Use td usage -q for subsequent reads.
|
|
||||||
|
|
||||||
**Generated:** 2026-02-14
|
|
||||||
**Commit:** dc2f3b6
|
|
||||||
**Branch:** master
|
|
||||||
|
|
||||||
## OVERVIEW
|
|
||||||
|
|
||||||
Personal Nix flake: custom packages, overlays, NixOS/Home Manager modules, dev shells. Flakes-only (no channels).
|
|
||||||
|
|
||||||
## STRUCTURE
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── flake.nix # Entry: packages, overlays, modules, shells, lib
|
|
||||||
├── pkgs/ # Custom packages (one dir each, callPackage registry)
|
|
||||||
├── modules/
|
|
||||||
│ ├── nixos/ # System modules (ports.nix)
|
|
||||||
│ └── home-manager/ # User modules by category (cli/, coding/, ports.nix)
|
|
||||||
├── lib/ # Shared utilities (ports.nix)
|
|
||||||
├── shells/ # Dev environments (default, python, devops)
|
|
||||||
├── overlays/mods/ # Package modifications (n8n version bump)
|
|
||||||
├── templates/ # Boilerplate for new packages/modules
|
|
||||||
├── examples/ # Usage examples
|
|
||||||
└── .gitea/workflows/ # CI/CD workflows (nix-update automation)
|
|
||||||
```
|
|
||||||
|
|
||||||
## WHERE TO LOOK
|
|
||||||
|
|
||||||
| Task | Location | Notes |
|
|
||||||
| -------------------- | ---------------------------------- | ------------------------------------- |
|
|
||||||
| Add package | `pkgs/<name>/default.nix` | Register in `pkgs/default.nix` |
|
|
||||||
| Add NixOS module | `modules/nixos/<name>.nix` | Import in `modules/nixos/default.nix` |
|
|
||||||
| Add HM module | `modules/home-manager/<category>/` | Category: cli, coding, or root |
|
|
||||||
| Override nixpkgs pkg | `overlays/mods/<name>.nix` | Import in `overlays/mods/default.nix` |
|
|
||||||
| Add dev shell | `shells/<name>.nix` | Register in `shells/default.nix` |
|
|
||||||
| Use port management | `config.m3ta.ports.get "service"` | Host-specific via `hostOverrides` |
|
|
||||||
| CI/CD workflows | `.gitea/workflows/<name>.yml` | Automated package updates (nix-update) |
|
|
||||||
|
|
||||||
## CONVENTIONS
|
|
||||||
|
|
||||||
**Formatter**: `nix fmt` before commit (alejandra)
|
|
||||||
|
|
||||||
**Naming**:
|
|
||||||
|
|
||||||
- Packages: `lowercase-hyphen` (e.g., `hyprpaper-random`)
|
|
||||||
- Variables: `camelCase` (e.g., `portHelpers`)
|
|
||||||
- Module options: `m3ta.*` namespace
|
|
||||||
|
|
||||||
**Imports**: Multi-line, trailing commas:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
lib,
|
|
||||||
stdenv,
|
|
||||||
fetchFromGitHub,
|
|
||||||
}:
|
|
||||||
```
|
|
||||||
|
|
||||||
**Modules**: Standard pattern:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{ config, lib, pkgs, ... }:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.m3ta.myModule;
|
|
||||||
in {
|
|
||||||
options.m3ta.myModule = {
|
|
||||||
enable = mkEnableOption "description";
|
|
||||||
};
|
|
||||||
config = mkIf cfg.enable { ... };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Meta**: Always include all fields:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
meta = with lib; {
|
|
||||||
description = "...";
|
|
||||||
homepage = "...";
|
|
||||||
license = licenses.mit;
|
|
||||||
platforms = platforms.linux;
|
|
||||||
mainProgram = "...";
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## PACKAGE PATTERNS
|
|
||||||
|
|
||||||
**Rust**: `rustPlatform.buildRustPackage rec { cargoLock.lockFile = src + "/Cargo.lock"; }`
|
|
||||||
|
|
||||||
**Shell**: `writeShellScriptBin "name" ''script''` or `mkDerivation` with custom `installPhase`
|
|
||||||
|
|
||||||
**AppImage**: `appimageTools.wrapType2 { ... }`
|
|
||||||
|
|
||||||
**Custom fetcher**: `fetchFromGitea { domain = "code.m3ta.dev"; owner = "m3tam3re"; ... }`
|
|
||||||
|
|
||||||
## MODULE PATTERNS
|
|
||||||
|
|
||||||
**Simple**: `options.cli.name = { enable = mkEnableOption "..."; }; config = mkIf cfg.enable { ... };`
|
|
||||||
|
|
||||||
**Multiple**: `config = mkMerge [ (mkIf cfg.x.enable { ... }) (mkIf cfg.y.enable { ... }) ];`
|
|
||||||
|
|
||||||
**Shared lib**: `portsLib = import ../../lib/ports.nix { inherit lib; }; portHelpers = portsLib.mkPortHelpers { ... };`
|
|
||||||
|
|
||||||
## LIBRARY FUNCTIONS
|
|
||||||
|
|
||||||
### `lib.ports`
|
|
||||||
|
|
||||||
Port management utilities. See [Port Management](#port-management).
|
|
||||||
|
|
||||||
### `lib.agents`
|
|
||||||
|
|
||||||
Harness-agnostic agent management. Reads canonical `agent.toml` from the AGENTS
|
|
||||||
flake input and renders tool-specific configs.
|
|
||||||
|
|
||||||
**Functions:**
|
|
||||||
|
|
||||||
| Function | Purpose |
|
|
||||||
|----------|--------|
|
|
||||||
| `loadCanonical { agentsInput }` | Load canonical agents from AGENTS flake |
|
|
||||||
| `renderForOpencode { pkgs, canonical, modelOverrides }` | Render to OpenCode file-based agents |
|
|
||||||
| `renderForClaudeCode { pkgs, canonical, modelOverrides }` | Render to Claude Code agents + settings.json |
|
|
||||||
| `renderForPi { pkgs, canonical }` | Render to Pi AGENTS.md + SYSTEM.md |
|
|
||||||
| `renderForTool { pkgs, agentsInput, tool, modelOverrides }` | Dispatch to correct renderer |
|
|
||||||
| `shellHookForTool { pkgs, agentsInput, tool, modelOverrides }` | Generate devShell shellHook |
|
|
||||||
|
|
||||||
### `lib.coding-rules`
|
|
||||||
|
|
||||||
Coding rules injection (renamed from `lib.opencode-rules`). The old name still works.
|
|
||||||
|
|
||||||
| Function | Purpose |
|
|
||||||
|----------|--------|
|
|
||||||
| `mkCodingRules { agents, languages, concerns, frameworks }` | Generate rules config + shellHook |
|
|
||||||
| `mkOpencodeRules` | Backward-compat alias for `mkCodingRules` |
|
|
||||||
|
|
||||||
## PORT MANAGEMENT
|
|
||||||
|
|
||||||
Central port management: `config.m3ta.ports.get "service"` with host-specific via `hostOverrides`
|
|
||||||
|
|
||||||
Generated: `/etc/m3ta/ports.json` (NixOS), `~/.config/m3ta/ports.json` (HM)
|
|
||||||
|
|
||||||
## COMMANDS
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check # Validate flake
|
|
||||||
nix fmt # Format (alejandra)
|
|
||||||
nix build .#<pkg> # Build package
|
|
||||||
nix flake show # List outputs
|
|
||||||
nix develop # Enter dev shell
|
|
||||||
nix develop .#python # Python shell
|
|
||||||
nix develop .#devops # DevOps shell
|
|
||||||
|
|
||||||
# In dev shell only:
|
|
||||||
statix check . # Lint
|
|
||||||
deadnix . # Find dead code
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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 |
|
|
||||||
|
|
||||||
## COMMIT FORMAT
|
|
||||||
|
|
||||||
```
|
|
||||||
type: brief description
|
|
||||||
```
|
|
||||||
|
|
||||||
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `chore`
|
|
||||||
|
|
||||||
## NOTES
|
|
||||||
|
|
||||||
- **Hash fetching**: Use `lib.fakeHash` initially, build to get real hash
|
|
||||||
- **HM modules**: Category subdirs (`cli/`, `coding/`) have own `default.nix` aggregators
|
|
||||||
- **Ports module**: Different for NixOS vs HM (HM adds `generateEnvVars` option)
|
|
||||||
- **Overlays**: `modifications` overlay uses `{prev}:` pattern, not `{final, prev}:`
|
|
||||||
- **Dev shell tools**: `statix`, `deadnix` only available inside `nix develop`
|
|
||||||
- **Automated package updates**: Packages are automatically updated weekly via Gitea Actions using `nix-update`. Review PRs from the automation before merging. For urgent updates, manually run the workflow or update manually.
|
|
||||||
|
|
||||||
## Task Management
|
|
||||||
|
|
||||||
This project uses **td** for tracking tasks across AI coding sessions.
|
|
||||||
Run `td usage --new-session` at conversation start to see current work.
|
|
||||||
Use `td usage -q` for subsequent reads.
|
|
||||||
|
|
||||||
**Quick reference:**
|
|
||||||
|
|
||||||
- `td usage --new-session` - Start new session and view tasks
|
|
||||||
- `td usage -q` - Quick view of current tasks (subsequent reads)
|
|
||||||
- `td version` - Check version
|
|
||||||
|
|
||||||
For full workflow details, see the [td documentation](./docs/packages/td.md).
|
|
||||||
|
|
||||||
## MIGRATION: Agent System (OpenCode → Canonical TOML)
|
|
||||||
|
|
||||||
The agent system was migrated from embedded `agents.json` to harness-agnostic
|
|
||||||
canonical `agent.toml` + `system-prompt.md` in the AGENTS repo. Renderers in
|
|
||||||
`lib/agents.nix` generate tool-specific configs.
|
|
||||||
|
|
||||||
### What changed in this repo
|
|
||||||
|
|
||||||
- **`lib/agents.nix`**: New — 3 renderers (OpenCode, Claude Code, Pi) + dispatcher + shellHook
|
|
||||||
- **`lib/coding-rules.nix`**: Renamed from `opencode-rules.nix`, `mkCodingRules` replaces `mkOpencodeRules`
|
|
||||||
- **`modules/home-manager/coding/agents/`**: New — per-tool HM sub-modules
|
|
||||||
- **`modules/home-manager/coding/opencode.nix`**: Slimmed — no longer handles agents/skills/context
|
|
||||||
- **`flake.nix`**: Exports new `agents` HM module
|
|
||||||
|
|
||||||
### What the user must do
|
|
||||||
|
|
||||||
See `modules/home-manager/AGENTS.md` for the full migration guide. Summary:
|
|
||||||
|
|
||||||
1. Move `agentsInput`/`externalSkills` from `coding.opencode` to `coding.agents.opencode`
|
|
||||||
2. Add `modelOverrides` with previously hardcoded model strings
|
|
||||||
3. Run `home-manager switch`
|
|
||||||
4. Remove legacy `agents.json` + `prompts/*.txt` from AGENTS repo
|
|
||||||
5. Remove `lib.agentsJson` backward-compat bridge from AGENTS `flake.nix`
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
This repository is being used as a Dolt remote.
|
||||||
|
|
||||||
|
ref=refs/dolt/data
|
||||||
|
|
||||||
|
head=43d141bca1faebdf2ed20deb3c147ca1b2946eea
|
||||||
|
|
||||||
|
timestamp=2026-07-04T07:30:30Z
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
| Package | Description |
|
|
||||||
| ------------------ | ------------------------------------- |
|
|
||||||
| `code2prompt` | Convert code to prompts |
|
|
||||||
| `hyprpaper-random` | Random wallpaper setter for Hyprpaper |
|
|
||||||
| `kestractl` | CLI for the Kestra workflow orchestration platform |
|
|
||||||
| `launch-webapp` | Launch web applications |
|
|
||||||
| `mem0` | AI memory assistant with vector storage |
|
|
||||||
| `msty-studio` | Msty Studio application |
|
|
||||||
| `n8n` | Free and source-available fair-code licensed workflow automation tool |
|
|
||||||
| `notesmd-cli` | Obsidian CLI (Community) - Interact with Obsidian in the terminal |
|
|
||||||
| `opencode-desktop` | OpenCode Desktop App with Wayland support (includes workaround for upstream issue #11755) |
|
|
||||||
| `pomodoro-timer` | Pomodoro timer utility |
|
|
||||||
| `rofi-project-opener` | Rofi-based project launcher |
|
|
||||||
| `sidecar` | Companion tool for CLI agents with diffs, file trees, and task management |
|
|
||||||
| `stt-ptt` | Push to Talk Speech to Text |
|
|
||||||
| `td` | Minimalist CLI for tracking tasks across AI coding sessions |
|
|
||||||
| `tuxedo-backlight` | Backlight control for Tuxedo laptops |
|
|
||||||
| `zellij-ps` | Project switcher for Zellij |
|
|
||||||
|
|
||||||
## 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)
|
|
||||||
@@ -1,473 +0,0 @@
|
|||||||
# 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`).
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
# 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
|
|
||||||
-155
@@ -1,155 +0,0 @@
|
|||||||
# 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
|
|
||||||
- [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
|
|
||||||
|
|
||||||
Documentation for all custom packages:
|
|
||||||
|
|
||||||
- [code2prompt](./packages/code2prompt.md) - Convert code to prompts
|
|
||||||
- [hyprpaper-random](./packages/hyprpaper-random.md) - Random wallpaper setter for Hyprpaper
|
|
||||||
- [kestractl](./packages/kestractl.md) - CLI for the Kestra workflow orchestration platform
|
|
||||||
- [launch-webapp](./packages/launch-webapp.md) - Launch web applications
|
|
||||||
- [mem0](./packages/mem0.md) - AI memory assistant with vector storage
|
|
||||||
- [msty-studio](./packages/msty-studio.md) - Msty Studio application
|
|
||||||
- [n8n](./packages/n8n.md) - Free and source-available fair-code licensed workflow automation tool
|
|
||||||
- [notesmd-cli](./packages/notesmd-cli.md) - Obsidian CLI (Community) - Interact with Obsidian in the terminal
|
|
||||||
- [pomodoro-timer](./packages/pomodoro-timer.md) - Pomodoro timer utility
|
|
||||||
- [rofi-project-opener](./packages/rofi-project-opener.md) - Rofi-based project launcher with custom args
|
|
||||||
- [sidecar](./packages/sidecar.md) - Companion tool for CLI agents with diffs, file trees, and task management
|
|
||||||
- [stt-ptt](./packages/stt-ptt.md) - Push to Talk Speech to Text using Whisper
|
|
||||||
- [td](./packages/td.md) - Minimalist CLI for tracking tasks across AI coding sessions
|
|
||||||
- [tuxedo-backlight](./packages/tuxedo-backlight.md) - Backlight control for Tuxedo laptops
|
|
||||||
- [zellij-ps](./packages/zellij-ps.md) - Project switcher for Zellij
|
|
||||||
|
|
||||||
### ⚙️ 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
|
|
||||||
|
|
||||||
## 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)
|
|
||||||
@@ -1,504 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,527 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,402 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
# Pi Agent Isolation (two-repo setup)
|
|
||||||
|
|
||||||
This guide documents the split setup where:
|
|
||||||
|
|
||||||
- `m3ta-nixpkgs` provides reusable module logic.
|
|
||||||
- `nixos-config` consumes it on specific hosts.
|
|
||||||
|
|
||||||
## 1) In `m3ta-nixpkgs`
|
|
||||||
|
|
||||||
Use:
|
|
||||||
|
|
||||||
- Home Manager module: `coding.agents.pi`
|
|
||||||
- renders Pi config in user space (default path: `.pi/agent` => `~/.pi/agent`)
|
|
||||||
- NixOS module: `m3ta.pi-agent`
|
|
||||||
- dedicated user/group (default `pi-agent`)
|
|
||||||
- state directory (default `/var/lib/pi-agent`)
|
|
||||||
- hardened execution via transient `systemd-run`
|
|
||||||
- host-side wrapper command (default `pi`)
|
|
||||||
- per-user allowlists via `hostUsers.<name>.projectRoots`
|
|
||||||
- host config sync into isolated runtime (default source `.pi/agent`)
|
|
||||||
- managed settings/env merge into isolated runtime
|
|
||||||
|
|
||||||
## 2) In consumer repo (`nixos-config`)
|
|
||||||
|
|
||||||
### Home Manager side
|
|
||||||
|
|
||||||
Keep Pi config rendering enabled for your normal user:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
coding.agents.pi = {
|
|
||||||
enable = true;
|
|
||||||
agentsInput = inputs.agents;
|
|
||||||
path = ".pi/agent";
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### NixOS host side (example: `m3-kratos`)
|
|
||||||
|
|
||||||
Enable isolated wrapper execution:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
m3ta.pi-agent = {
|
|
||||||
enable = true;
|
|
||||||
stateDir = "/var/lib/pi-agent";
|
|
||||||
|
|
||||||
hostUsers = {
|
|
||||||
m3tam3re = {
|
|
||||||
projectRoots = ["~/p" "~/work/private"];
|
|
||||||
# optional; defaults to wrapper.hostConfigPath
|
|
||||||
configPath = ".pi/agent";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
settings = {
|
|
||||||
defaultProvider = "anthropic";
|
|
||||||
defaultModel = "anthropic/claude-sonnet-4";
|
|
||||||
quietStartup = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
PI_TELEMETRY = "0";
|
|
||||||
};
|
|
||||||
|
|
||||||
environmentFiles = [
|
|
||||||
"/run/secrets/pi-agent.env"
|
|
||||||
];
|
|
||||||
|
|
||||||
wrapper = {
|
|
||||||
enable = true;
|
|
||||||
commandName = "pi";
|
|
||||||
hideDirectBinary = true;
|
|
||||||
hostConfigPath = ".pi/agent";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3) Authorization model
|
|
||||||
|
|
||||||
The wrapper uses a tightly scoped sudo rule:
|
|
||||||
|
|
||||||
- authorized users may run only the privileged runner command
|
|
||||||
- with `NOPASSWD`
|
|
||||||
- no broad `NOPASSWD: ALL`
|
|
||||||
|
|
||||||
## 4) Merge behavior
|
|
||||||
|
|
||||||
At invocation time, isolated runtime files are built from:
|
|
||||||
|
|
||||||
1. Host user Pi config (synced from source path, e.g. `~/.pi/agent`)
|
|
||||||
2. Nix-managed settings/env (override host values)
|
|
||||||
3. Environment files (appended after managed env attrs)
|
|
||||||
|
|
||||||
This keeps user-authored Pi config available while allowing reproducible Nix overrides.
|
|
||||||
|
|
||||||
## 5) Migration notes
|
|
||||||
|
|
||||||
- If wrapper mode is canonical, remove direct `pi-coding-agent` from user package lists to reduce command-path ambiguity.
|
|
||||||
- Rebuild host config and test from an allowlisted project path.
|
|
||||||
- Validate `pi` process identity runs as `pi-agent`.
|
|
||||||
@@ -1,525 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,693 +0,0 @@
|
|||||||
# 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)
|
|
||||||
|
|
||||||
#### `m3ta.pi-agent`
|
|
||||||
|
|
||||||
Isolated Pi execution with a dedicated system user (`pi-agent` by default),
|
|
||||||
a hardened runtime, and a host-side `pi` wrapper command.
|
|
||||||
|
|
||||||
```nix
|
|
||||||
m3ta.pi-agent = {
|
|
||||||
enable = true;
|
|
||||||
stateDir = "/var/lib/pi-agent";
|
|
||||||
|
|
||||||
hostUsers = {
|
|
||||||
m3tam3re = {
|
|
||||||
projectRoots = ["~/p" "~/work/private"];
|
|
||||||
configPath = ".pi/agent"; # optional
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
settings.defaultModel = "anthropic/claude-sonnet-4";
|
|
||||||
environment.PI_TELEMETRY = "0";
|
|
||||||
wrapper.commandName = "pi";
|
|
||||||
wrapper.hideDirectBinary = true;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Documentation**: [Pi Agent Isolation Guide](./pi-agent-isolation.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;
|
|
||||||
path = ".pi/agent"; # default; can be changed
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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
|
|
||||||
- [Architecture](../ARCHITECTURE.md) - Understanding module structure
|
|
||||||
- [Contributing](../CONTRIBUTING.md) - Code style and guidelines
|
|
||||||
@@ -1,219 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,312 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,317 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,508 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# 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
|
|
||||||
```
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
# msty-studio
|
|
||||||
|
|
||||||
Msty Studio enables advanced, privacy‑preserving 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
|
|
||||||
@@ -1,310 +0,0 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
### Via Overlay
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{pkgs, ...}: {
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
n8n
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Direct Reference
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{pkgs, ...}: {
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
inputs.m3ta-nixpkgs.packages.${pkgs.system}.n8n
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run Directly
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#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.4.1
|
|
||||||
- **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
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
# notesmd-cli
|
|
||||||
|
|
||||||
Obsidian CLI (Community) - Interact with Obsidian in the terminal.
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
notesmd-cli is a command-line interface for interacting with Obsidian, the popular knowledge management and note-taking application. It allows you to create, search, and manipulate notes directly from the terminal.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- 📝 **Note Creation**: Create new notes from the command line
|
|
||||||
- 🔍 **Search**: Search through your Obsidian vault
|
|
||||||
- 📂 **Vault Management**: Interact with your vault structure
|
|
||||||
- 🔗 **WikiLink Support**: Work with Obsidian's WikiLink format
|
|
||||||
- 🏷️ **Tag Support**: Manage and search by tags
|
|
||||||
- ⚡ **Fast**: Lightweight Go binary with no external dependencies
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### Via Overlay
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{pkgs, ...}: {
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
notesmd-cli
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Direct Reference
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{pkgs, ...}: {
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
inputs.m3ta-nixpkgs.packages.${pkgs.system}.notesmd-cli
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run Directly
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#notesmd-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Basic Commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Show help
|
|
||||||
notesmd-cli --help
|
|
||||||
|
|
||||||
# Create a new note
|
|
||||||
notesmd-cli new "My Note Title"
|
|
||||||
|
|
||||||
# Search notes
|
|
||||||
notesmd-cli search "search term"
|
|
||||||
|
|
||||||
# List notes
|
|
||||||
notesmd-cli list
|
|
||||||
```
|
|
||||||
|
|
||||||
### Working with Vaults
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Specify vault path
|
|
||||||
notesmd-cli --vault /path/to/vault new "Note Title"
|
|
||||||
|
|
||||||
# Open a note in Obsidian
|
|
||||||
notesmd-cli open "Note Name"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Advanced Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Search with tags
|
|
||||||
notesmd-cli search --tag "project"
|
|
||||||
|
|
||||||
# Append to existing note
|
|
||||||
notesmd-cli append "Note Name" "Additional content"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Environment Variables
|
|
||||||
|
|
||||||
- `OBSIDIAN_VAULT`: Default vault path
|
|
||||||
|
|
||||||
### Command Line Options
|
|
||||||
|
|
||||||
Run `notesmd-cli --help` for a complete list of options.
|
|
||||||
|
|
||||||
## Build Information
|
|
||||||
|
|
||||||
- **Version**: 0.3.0
|
|
||||||
- **Language**: Go
|
|
||||||
- **License**: MIT
|
|
||||||
- **Source**: [GitHub](https://github.com/Yakitrak/notesmd-cli)
|
|
||||||
- **Vendor Hash**: null (no external dependencies)
|
|
||||||
|
|
||||||
## Platform Support
|
|
||||||
|
|
||||||
- Linux
|
|
||||||
- macOS (Unix systems)
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- No vendor dependencies (pure Go stdlib)
|
|
||||||
- The binary is named `notesmd-cli` (not `notesmd`)
|
|
||||||
- This is the community CLI, not the official Obsidian CLI
|
|
||||||
|
|
||||||
## Related
|
|
||||||
|
|
||||||
- [Obsidian](https://obsidian.md) - The Obsidian application
|
|
||||||
- [Adding Packages](../guides/adding-packages.md) - How to add new packages
|
|
||||||
- [Quick Start](../QUICKSTART.md) - Getting started guide
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,248 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,637 +0,0 @@
|
|||||||
# m3ta-nixpkgs: Cleanup & Improvements Plan
|
|
||||||
|
|
||||||
> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.
|
|
||||||
|
|
||||||
**Goal:** Address 10 issues identified in codebase review — reduce duplication, improve naming consistency, extract inline scripts, add testing, and update documentation.
|
|
||||||
|
|
||||||
**Architecture:** Incremental improvements across lib/, modules/, overlays/, docs/, and CI. Each change is self-contained and can be merged independently. No breaking changes to public API (backward-compat aliases preserved where needed).
|
|
||||||
|
|
||||||
**Repo:** `gitea@code.m3ta.dev:m3tam3re/nixpkgs.git` (master branch)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 1: Deduplication & Naming (Low Risk)
|
|
||||||
|
|
||||||
### Task 1: Remove duplicate opencode-rules.nix file
|
|
||||||
|
|
||||||
**Objective:** Eliminate the duplicate file import. The `coding-rules.nix` is the canonical source; `opencode-rules.nix` is an identical copy. Make the alias a one-liner in `lib/default.nix`.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Delete: `lib/opencode-rules.nix`
|
|
||||||
- Modify: `lib/default.nix`
|
|
||||||
|
|
||||||
**Step 1: Update lib/default.nix to alias directly**
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{lib}: {
|
|
||||||
ports = import ./ports.nix {inherit lib;};
|
|
||||||
|
|
||||||
coding-rules = import ./coding-rules.nix {inherit lib;};
|
|
||||||
|
|
||||||
# Backward-compat alias: opencode-rules → coding-rules
|
|
||||||
opencode-rules = import ./coding-rules.nix {inherit lib;};
|
|
||||||
opencode = import ./coding-rules.nix {inherit lib;};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: Delete the duplicate file**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git rm lib/opencode-rules.nix
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 3: Verify nothing breaks**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -m "refactor: remove duplicate opencode-rules.nix, use alias in default.nix"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 2: Tool-agnostic naming in coding-rules.nix internals
|
|
||||||
|
|
||||||
**Objective:** Rename internal variables and output artifacts in `coding-rules.nix` from opencode-specific names to generic names, while keeping the backward-compat alias `mkOpencodeRules`.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `lib/coding-rules.nix`
|
|
||||||
|
|
||||||
**Step 1: Rename internal symbols**
|
|
||||||
|
|
||||||
In `lib/coding-rules.nix`, rename:
|
|
||||||
- `rulesDir` stays `.opencode-rules` (this is a filesystem path used by existing projects, changing it would break)
|
|
||||||
- `opencodeConfig` → `rulesConfig`
|
|
||||||
- `opencode.json` output → `coding-rules.json` (add a comment noting it was renamed)
|
|
||||||
- Add `rulesDir` option to function signature with default `.opencode-rules`
|
|
||||||
|
|
||||||
Updated function:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{lib}: let
|
|
||||||
mkCodingRules = {
|
|
||||||
agents,
|
|
||||||
languages ? [],
|
|
||||||
concerns ? [
|
|
||||||
"coding-style"
|
|
||||||
"naming"
|
|
||||||
"documentation"
|
|
||||||
"testing"
|
|
||||||
"git-workflow"
|
|
||||||
"project-structure"
|
|
||||||
],
|
|
||||||
frameworks ? [],
|
|
||||||
extraInstructions ? [],
|
|
||||||
rulesDir ? ".opencode-rules",
|
|
||||||
}: let
|
|
||||||
instructions =
|
|
||||||
(map (c: "${rulesDir}/concerns/${c}.md") concerns)
|
|
||||||
++ (map (l: "${rulesDir}/languages/${l}.md") languages)
|
|
||||||
++ (map (f: "${rulesDir}/frameworks/${f}.md") frameworks)
|
|
||||||
++ extraInstructions;
|
|
||||||
|
|
||||||
rulesConfig = {
|
|
||||||
"$schema" = "https://opencode.ai/config.json";
|
|
||||||
inherit instructions;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
inherit instructions;
|
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
# Create/update symlink to AGENTS rules directory
|
|
||||||
ln -sfn ${agents}/rules ${rulesDir}
|
|
||||||
|
|
||||||
# Generate coding-rules configuration file
|
|
||||||
cat > coding-rules.json <<'RULES_EOF'
|
|
||||||
${builtins.toJSON rulesConfig}
|
|
||||||
RULES_EOF
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# Backward-compat alias
|
|
||||||
mkOpencodeRules = mkCodingRules;
|
|
||||||
in {
|
|
||||||
inherit mkCodingRules mkOpencodeRules;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: Update shellHook comment in AGENTS.md**
|
|
||||||
|
|
||||||
In `AGENTS.md`, update the coding-rules section to mention the new `rulesDir` parameter and the `coding-rules.json` output file.
|
|
||||||
|
|
||||||
**Step 3: Verify**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -m "refactor: tool-agnostic naming in coding-rules.nix internals"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 3: Remove redundant overlays entry in flake.nix
|
|
||||||
|
|
||||||
**Objective:** The `default` and `additions` overlays in `flake.nix` produce identical output. Remove `additions` if not referenced elsewhere, or document why both exist.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `flake.nix`
|
|
||||||
- Check: all consumer repos for references to `overlays.additions`
|
|
||||||
|
|
||||||
**Step 1: Search for consumers of overlays.additions**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Check nixos-config and other repos
|
|
||||||
grep -r "overlays.additions" /data/.hermes/repos/nixos-config/
|
|
||||||
grep -r "additions" /data/.hermes/repos/nixos-config/ --include="*.nix" | grep overlay
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: If no consumers found, remove additions**
|
|
||||||
|
|
||||||
In `flake.nix`, simplify overlays to:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
overlays = {
|
|
||||||
default = final: prev:
|
|
||||||
import ./pkgs {
|
|
||||||
pkgs = final;
|
|
||||||
inputs = inputs;
|
|
||||||
};
|
|
||||||
|
|
||||||
modifications = final: prev: import ./overlays/mods {inherit prev;};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 3: Verify**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -m "refactor: remove redundant 'additions' overlay (identical to 'default')"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Note:** If `additions` IS used elsewhere, add a comment explaining the convention and skip this task.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 2: Extract Inline Scripts (Medium Risk)
|
|
||||||
|
|
||||||
### Task 4: Extract pi-agent runner script to standalone file
|
|
||||||
|
|
||||||
**Objective:** Move the ~200-line inline bash script in `modules/nixos/pi-agent.nix` (the `runner` variable) to a separate file `modules/nixos/pi-agent-runner.sh` that gets imported via `builtins.readFile` + `pkgs.writeShellApplication`.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `modules/nixos/pi-agent-runner.sh`
|
|
||||||
- Modify: `modules/nixos/pi-agent.nix`
|
|
||||||
|
|
||||||
**Step 1: Create the runner script file**
|
|
||||||
|
|
||||||
Extract the body of the `runner` script (everything inside the `pkgs.writeShellScriptBin cfg.wrapper.runnerName '' ... ''`) into `modules/nixos/pi-agent-runner.sh`.
|
|
||||||
|
|
||||||
The script uses Nix-style variable interpolation (`${...}`). We need to keep Nix template variables as `${...}` and convert runtime bash variables to use `$` prefix. Since the script already uses Nix `escapeShellArg` and `escapeShellArg` calls, the cleanest approach is:
|
|
||||||
|
|
||||||
Create `modules/nixos/pi-agent-runner.sh` as a template that `pkgs.substituteAll` or `builtins.readFile` + string replacement can process. However, given the heavy Nix interpolation, the pragmatic approach is to use `pkgs.writeShellApplication` with the script body inline but extracted to a `let` binding:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# In pi-agent.nix, replace the inline runner with:
|
|
||||||
let
|
|
||||||
runnerScript = builtins.readFile ./pi-agent-runner.sh;
|
|
||||||
# ... or keep as let binding but move the body to a separate derivation
|
|
||||||
```
|
|
||||||
|
|
||||||
**Important caveat:** The script has ~30 Nix variable interpolations (`${cfg.user}`, `${escapeShellArg ...}`, etc.). Full extraction to a .sh file would require either:
|
|
||||||
- (a) `substituteAll` with `--replace` for each variable — unwieldy at 30+ substitutions
|
|
||||||
- (b) Converting to env vars passed at runtime — cleaner but changes security posture
|
|
||||||
- (c) Keeping the Nix interpolation but extracting to a `let` block in a separate `.nix` file
|
|
||||||
|
|
||||||
**Recommended approach: Option (c)** — Create `modules/nixos/pi-agent-runner.nix` as a function that takes `cfg` and returns the script:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# modules/nixos/pi-agent-runner.nix
|
|
||||||
{cfg, pkgs, lib, ...}:
|
|
||||||
with lib; let
|
|
||||||
# ... all the helper variables from pi-agent.nix ...
|
|
||||||
in
|
|
||||||
pkgs.writeShellScriptBin cfg.wrapper.runnerName ''
|
|
||||||
# ... the script body ...
|
|
||||||
'';
|
|
||||||
```
|
|
||||||
|
|
||||||
Then in `pi-agent.nix`:
|
|
||||||
```nix
|
|
||||||
runner = import ./pi-agent-runner.nix {inherit cfg pkgs lib;};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: Similarly extract the wrapper script**
|
|
||||||
|
|
||||||
Create `modules/nixos/pi-agent-wrapper.nix` for the `wrapper` variable.
|
|
||||||
|
|
||||||
**Step 3: Verify**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check
|
|
||||||
# Also test in a nixos-rebuild if possible
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add modules/nixos/pi-agent-runner.nix modules/nixos/pi-agent-wrapper.nix
|
|
||||||
git commit -m "refactor: extract pi-agent runner and wrapper to separate files"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 3: Testing (Higher Value)
|
|
||||||
|
|
||||||
### Task 5: Add basic lib function tests
|
|
||||||
|
|
||||||
**Objective:** Add `nix eval`-based tests for `lib/agents.nix` parseRule logic and `lib/coding-rules.nix` instruction generation.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `tests/lib/agents-test.nix`
|
|
||||||
- Create: `tests/lib/coding-rules-test.nix`
|
|
||||||
- Modify: `flake.nix` (add checks)
|
|
||||||
|
|
||||||
**Step 1: Create test infrastructure**
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# tests/lib/default.nix
|
|
||||||
{
|
|
||||||
agents = import ./agents-test.nix;
|
|
||||||
coding-rules = import ./coding-rules-test.nix;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: Write agents.nix parseRule test**
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# tests/lib/agents-test.nix
|
|
||||||
let
|
|
||||||
lib = import <nixpkgs/lib>;
|
|
||||||
agentsLib = (import ../../lib {inherit lib;}).agents;
|
|
||||||
|
|
||||||
# Test parseRule helper
|
|
||||||
test1 = let
|
|
||||||
result = builtins.tryEval (
|
|
||||||
let
|
|
||||||
# We can't directly test parseRule since it's internal.
|
|
||||||
# Instead, test the renderer with minimal input.
|
|
||||||
canonical = {
|
|
||||||
test-agent = {
|
|
||||||
description = "Test agent";
|
|
||||||
mode = "primary";
|
|
||||||
systemPrompt = "You are a test.";
|
|
||||||
permissions = {
|
|
||||||
bash = { intent = "allow"; };
|
|
||||||
edit = { intent = "ask"; rules = ["rm -rf *:deny"]; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
pkgs = import <nixpkgs> { system = "x86_64-linux"; };
|
|
||||||
rendered = agentsLib.renderForOpencode {
|
|
||||||
inherit pkgs canonical;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
# Verify the derivation builds
|
|
||||||
builtins.pathExists "${rendered}/test-agent.md"
|
|
||||||
);
|
|
||||||
in assert result.value == true; true;
|
|
||||||
|
|
||||||
in {
|
|
||||||
parseRule-basic = test1;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 3: Write coding-rules test**
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# tests/lib/coding-rules-test.nix
|
|
||||||
let
|
|
||||||
lib = import <nixpkgs/lib>;
|
|
||||||
codingRulesLib = (import ../../lib {inherit lib;}).coding-rules;
|
|
||||||
|
|
||||||
rules = codingRulesLib.mkCodingRules {
|
|
||||||
agents = "/tmp/fake-agents";
|
|
||||||
languages = ["python"];
|
|
||||||
concerns = ["naming"];
|
|
||||||
rulesDir = ".coding-rules";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Verify instructions are generated correctly
|
|
||||||
test1 = assert rules.instructions == [
|
|
||||||
".coding-rules/concerns/naming.md"
|
|
||||||
".coding-rules/languages/python.md"
|
|
||||||
]; true;
|
|
||||||
|
|
||||||
# Verify backward-compat alias exists
|
|
||||||
test2 = assert codingRulesLib.mkOpencodeRules == codingRulesLib.mkCodingRules; true;
|
|
||||||
|
|
||||||
in {
|
|
||||||
instructions-correct = test1;
|
|
||||||
backward-compat = test2;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 4: Add to flake.nix checks**
|
|
||||||
|
|
||||||
In `flake.nix`, extend the `checks` attribute:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
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
|
|
||||||
'';
|
|
||||||
lib-tests = pkgs.runCommand "lib-tests" {} ''
|
|
||||||
${pkgs.nix}/bin/nix-instantiate --eval ${./tests/lib/default.nix}
|
|
||||||
touch $out
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 5: Verify**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 6: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add tests/
|
|
||||||
git commit -m "test: add basic lib function tests for agents and coding-rules"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 6: Add NixOS VM test for pi-agent module
|
|
||||||
|
|
||||||
**Objective:** Add a basic NixOS VM test that verifies the pi-agent module can be evaluated and the wrapper/runner scripts exist.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `tests/nixos/pi-agent-test.nix`
|
|
||||||
- Modify: `flake.nix` (add to checks)
|
|
||||||
|
|
||||||
**Step 1: Write the VM test**
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# tests/nixos/pi-agent-test.nix
|
|
||||||
{pkgs, ...}: {
|
|
||||||
name = "pi-agent";
|
|
||||||
|
|
||||||
nodes.machine = {config, ...}: {
|
|
||||||
imports = [
|
|
||||||
${(pkgs.path + "/nixos/modules/module-list.nix")}
|
|
||||||
];
|
|
||||||
|
|
||||||
# Minimal pi-agent config
|
|
||||||
m3ta.pi-agent = {
|
|
||||||
enable = true;
|
|
||||||
package = pkgs.writeScriptBin "pi-agent" ''
|
|
||||||
#!/bin/sh
|
|
||||||
echo "pi-agent mock"
|
|
||||||
'';
|
|
||||||
createUser = true;
|
|
||||||
hostUsers = {
|
|
||||||
testuser = {
|
|
||||||
projectRoots = ["/tmp/test-project"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
users.users.testuser = {
|
|
||||||
isNormalUser = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
testScript = ''
|
|
||||||
machine.start()
|
|
||||||
machine.wait_for_unit("multi-user.target")
|
|
||||||
|
|
||||||
# Verify user was created
|
|
||||||
machine.succeed("id pi-agent")
|
|
||||||
|
|
||||||
# Verify wrapper exists
|
|
||||||
machine.succeed("which pi")
|
|
||||||
|
|
||||||
# Verify state directory
|
|
||||||
machine.succeed("test -d /var/lib/pi-agent")
|
|
||||||
machine.succeed("test -d /var/lib/pi-agent/.pi")
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: Add to flake.nix checks**
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# In the checks attrset:
|
|
||||||
pi-agent-vm-test = pkgs.nixosTest (import ./tests/nixos/pi-agent-test.nix {inherit pkgs;});
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 3: Verify**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix build .#checks.x86_64-linux.pi-agent-vm-test
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 4: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add tests/nixos/
|
|
||||||
git commit -m "test: add NixOS VM test for pi-agent module"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 4: Documentation (Low Risk, High Value)
|
|
||||||
|
|
||||||
### Task 7: Update AGENTS.md to reflect current state
|
|
||||||
|
|
||||||
**Objective:** Remove outdated migration sections, update function signatures, and align with current code.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `AGENTS.md`
|
|
||||||
|
|
||||||
**Step 1: Update the AGENTS REWORK migration section**
|
|
||||||
|
|
||||||
The section starting with `## MIGRATION: Agent System (OpenCode → Canonical TOML)` describes a completed migration. Convert it to a brief "Architecture" section that describes the current state, not the migration path.
|
|
||||||
|
|
||||||
**Step 2: Update lib.agents function table**
|
|
||||||
|
|
||||||
Verify that the function signatures and descriptions in the AGENTS.md table match the actual functions in `lib/agents.nix`. Specifically:
|
|
||||||
- `loadCanonical` takes `{agentsInput}` — confirm docs match
|
|
||||||
- `renderForPi` now has `primaryAgent` parameter — confirm documented
|
|
||||||
- `shellHookForTool` exists — confirm documented
|
|
||||||
|
|
||||||
**Step 3: Update coding-rules documentation**
|
|
||||||
|
|
||||||
Replace references to `mkOpencodeRules` with `mkCodingRules` as primary, `mkOpencodeRules` as backward-compat alias. Document the new `rulesDir` parameter.
|
|
||||||
|
|
||||||
**Step 4: Update overlay documentation**
|
|
||||||
|
|
||||||
Remove or annotate the `additions` overlay depending on Task 3 outcome.
|
|
||||||
|
|
||||||
**Step 5: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -m "docs: update AGENTS.md to reflect current codebase state"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 8: Add CHANGELOG.md
|
|
||||||
|
|
||||||
**Objective:** Create a changelog that captures recent work (from git log) so consumers can track changes.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `CHANGELOG.md`
|
|
||||||
|
|
||||||
**Step 1: Generate changelog from git history**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /data/.hermes/repos/nixpkgs-review
|
|
||||||
git log --oneline --no-merges master | head -30
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: Write CHANGELOG.md**
|
|
||||||
|
|
||||||
Structure as Keep a Changelog format:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# 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]
|
|
||||||
|
|
||||||
## [0.4.0] - 2026-04-15
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Pi agent wrapper with per-host-user policy enforcement (`m3ta.pi-agent` NixOS module)
|
|
||||||
- `coding.agents.pi` Home Manager module with settings, MCP, and skills support
|
|
||||||
- `coding.agents.claude-code` Home Manager module with MCP integration
|
|
||||||
- Automated package updates via Gitea Actions (`nix-update` workflow)
|
|
||||||
- `lib.agents.renderForPi` with primaryAgent selection and pi-subagents format
|
|
||||||
- `pkgs/td` - Task management CLI for AI coding sessions
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- Renamed `lib.opencode-rules` → `lib.coding-rules` (backward-compat alias preserved)
|
|
||||||
- Agent system migrated to harness-agnostic canonical format
|
|
||||||
- Pi settings sync now merges host and Nix-managed values via deep_merge
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- Pi settings sync race condition on first run
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 3: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -m "docs: add CHANGELOG.md"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Phase 5: Minor Cleanups (Low Risk)
|
|
||||||
|
|
||||||
### Task 9: Clean up pkgs/default.nix unused `system` binding
|
|
||||||
|
|
||||||
**Objective:** The `system = pkgs.stdenv.hostPlatform.system;` binding in `pkgs/default.nix` is only used for the two input-pass-throughs. If those are the only consumers, it's fine, but add a clarifying comment.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `pkgs/default.nix`
|
|
||||||
|
|
||||||
**Step 1: Add clarifying comment**
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
pkgs,
|
|
||||||
inputs,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
# Only used for flake input pass-throughs below
|
|
||||||
system = pkgs.stdenv.hostPlatform.system;
|
|
||||||
in {
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 2: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -m "docs: clarify system binding in pkgs/default.nix"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 10: Remove commented-out overlay entries in overlays/default.nix
|
|
||||||
|
|
||||||
**Objective:** Clean up the large block of commented-out code in `overlays/default.nix` (nodejs_24, paperless-ngx, anytype-heart, hyprpanel, etc.). These belong in git history, not in active code.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `overlays/default.nix`
|
|
||||||
|
|
||||||
**Step 1: Remove commented-out blocks**
|
|
||||||
|
|
||||||
Remove:
|
|
||||||
- The `rose-pine-hyprcursor` addition from `additions` (if it's unused — check with grep)
|
|
||||||
- The commented-out `nodejs_24`, `paperless-ngx`, `anytype-heart`, `trezord`, `mesa`, `hyprpanel` blocks from `modifications`
|
|
||||||
- The commented-out overlay inputs (`temp-packages`, `stable-packages`, `pinned-packages`, `locked-packages`, `master-packages`) if they reference inputs not in `flake.nix`
|
|
||||||
|
|
||||||
Actually, `nixpkgs-stable`, `nixpkgs-9e9486b`, `nixpkgs-9472de4`, `nixpkgs-locked`, `nixpkgs-master` are NOT in the current `flake.nix` inputs. These overlays will fail if referenced. They should either be removed or the inputs should be added.
|
|
||||||
|
|
||||||
**Action:**
|
|
||||||
- Keep `master-packages` IF `nixpkgs-master` is in flake.nix inputs (it IS — good)
|
|
||||||
- Remove `temp-packages`, `pinned-packages`, `locked-packages` (inputs don't exist)
|
|
||||||
- Keep `stable-packages` IF `nixpkgs-stable` exists in inputs (check — it does NOT currently exist)
|
|
||||||
- Keep `additions` with `rose-pine-hyprcursor` IF `rose-pine-hyprcursor` input exists (check)
|
|
||||||
|
|
||||||
**Step 2: Verify**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check
|
|
||||||
```
|
|
||||||
|
|
||||||
**Step 3: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git commit -m "chore: remove dead overlay entries for non-existent flake inputs"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Execution Order & Priority
|
|
||||||
|
|
||||||
| Task | Risk | Effort | Impact | Dependencies |
|
|
||||||
|------|------|--------|--------|-------------|
|
|
||||||
| T1: Remove opencode-rules.nix | Low | 5min | Clean | None |
|
|
||||||
| T2: Tool-agnostic naming | Low | 15min | Consistency | None |
|
|
||||||
| T3: Remove redundant overlay | Low | 10min | Clean | Check consumers |
|
|
||||||
| T9: Clarify system binding | Low | 2min | Docs | None |
|
|
||||||
| T10: Remove dead overlays | Low | 10min | Clean | None |
|
|
||||||
| T7: Update AGENTS.md | Low | 20min | Docs | After T1, T2 |
|
|
||||||
| T8: Add CHANGELOG.md | Low | 15min | Docs | None |
|
|
||||||
| T4: Extract pi-agent scripts | Medium | 45min | Maintainability | None |
|
|
||||||
| T5: Lib function tests | Medium | 30min | Quality | None |
|
|
||||||
| T6: NixOS VM test | Medium | 45min | Quality | None |
|
|
||||||
|
|
||||||
**Recommended order:** T1 → T9 → T10 → T3 → T2 → T7 → T8 → T5 → T4 → T6
|
|
||||||
|
|
||||||
**Branching strategy:** Create a feature branch `chore/cleanup-review` from master, implement all tasks, open PR for review before merging.
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
# 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"]
|
|
||||||
```
|
|
||||||
|
|
||||||
### `getDefaultPort`
|
|
||||||
|
|
||||||
Simple helper to get a port without host override.
|
|
||||||
|
|
||||||
#### Signature
|
|
||||||
|
|
||||||
```nix
|
|
||||||
getDefaultPort :: portsConfig -> string -> int-or-null
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Arguments
|
|
||||||
|
|
||||||
1. `portsConfig` - Same structure as `mkPortHelpers`
|
|
||||||
2. `service` - The service name (string)
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
|
|
||||||
Port number (int) or `null` if service not found.
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
```nix
|
|
||||||
services.my-service = {
|
|
||||||
port = m3taLib.ports.getDefaultPort myPorts "my-service";
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## 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]` |
|
|
||||||
| `getDefaultPort` | Get default port only | `int or null` |
|
|
||||||
|
|
||||||
## 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
|
|
||||||
@@ -1,498 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
# 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;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
# 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
-109
@@ -1,109 +0,0 @@
|
|||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"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": 1775423009,
|
|
||||||
"narHash": "sha256-vPKLpjhIVWdDrfiUM8atW6YkIggCEKdSAlJPzzhkQlw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "68d8aa3d661f0e6bd5862291b5bb263b2a6595c9",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-master": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1775657231,
|
|
||||||
"narHash": "sha256-DP8FfybiZPp5WLB9eIk0TC2mdvuYzxLGgrBODDrwPEI=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "4e03baaa39b7746eac5704d623461422131cd03d",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "master",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"opencode": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs-master"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1775782812,
|
|
||||||
"narHash": "sha256-m+Ue7FWiTjKMAn1QefAwOMfOb2Vybk0mJPV9zcbkOmE=",
|
|
||||||
"owner": "anomalyco",
|
|
||||||
"repo": "opencode",
|
|
||||||
"rev": "877be7e8e04142cd8fbebcb5e6c4b9617bf28cce",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "anomalyco",
|
|
||||||
"ref": "v1.4.3",
|
|
||||||
"repo": "opencode",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"openspec": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1775372219,
|
|
||||||
"narHash": "sha256-MJakKC026Sarz7nMmiFrfONWc4xgaw8ApV0Hhp4ebhM=",
|
|
||||||
"owner": "Fission-AI",
|
|
||||||
"repo": "OpenSpec",
|
|
||||||
"rev": "64d476f8b924bb9b74b896ea0aa784970e37da69",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "Fission-AI",
|
|
||||||
"repo": "OpenSpec",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"basecamp": "basecamp",
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"nixpkgs-master": "nixpkgs-master",
|
|
||||||
"opencode": "opencode",
|
|
||||||
"openspec": "openspec"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
{
|
|
||||||
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";
|
|
||||||
};
|
|
||||||
|
|
||||||
# opencode needs newer bun from master
|
|
||||||
opencode = {
|
|
||||||
url = "github:anomalyco/opencode/v1.4.3";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs-master";
|
|
||||||
};
|
|
||||||
|
|
||||||
# openspec - spec-driven development for AI coding assistants
|
|
||||||
openspec = {
|
|
||||||
url = "github:Fission-AI/OpenSpec";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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 = {
|
|
||||||
# Default overlay: adds all custom packages
|
|
||||||
default = final: prev:
|
|
||||||
import ./pkgs {
|
|
||||||
pkgs = final;
|
|
||||||
inputs = inputs;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Individual overlays for more granular control
|
|
||||||
additions = final: prev:
|
|
||||||
import ./pkgs {
|
|
||||||
pkgs = final;
|
|
||||||
inputs = inputs;
|
|
||||||
};
|
|
||||||
|
|
||||||
modifications = final: prev: import ./overlays/mods {inherit prev;};
|
|
||||||
};
|
|
||||||
|
|
||||||
# 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;
|
|
||||||
pi-agent = ./modules/nixos/pi-agent.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: let
|
|
||||||
pkgs = pkgsFor system;
|
|
||||||
in
|
|
||||||
import ./lib {lib = pkgs.lib;});
|
|
||||||
|
|
||||||
# Development shells for various programming environments
|
|
||||||
# Usage: nix develop .#<shell-name>
|
|
||||||
# Available shells: default, python, devops, opencode
|
|
||||||
devShells = forAllSystems (system: let
|
|
||||||
pkgs = pkgsFor system;
|
|
||||||
in
|
|
||||||
import ./shells {inherit pkgs inputs;});
|
|
||||||
|
|
||||||
# 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
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
# 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";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
-419
@@ -1,419 +0,0 @@
|
|||||||
# 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;};
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
mkAgentFile = name: agent:
|
|
||||||
pkgs.writeText "${name}.md" (mkAgentContent name agent);
|
|
||||||
|
|
||||||
agentFiles = lib.mapAttrs mkAgentFile canonical;
|
|
||||||
|
|
||||||
copyCommands = lib.concatStringsSep "\n" (
|
|
||||||
lib.mapAttrsToList (name: file: "cp ${file} $out/${name}.md") agentFiles
|
|
||||||
);
|
|
||||||
in
|
|
||||||
pkgs.runCommand "opencode-agents" {} ''
|
|
||||||
mkdir -p $out
|
|
||||||
${copyCommands}
|
|
||||||
'';
|
|
||||||
|
|
||||||
# ── 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;
|
|
||||||
|
|
||||||
mkClaudeAgentFile = name: agent:
|
|
||||||
pkgs.writeText "${name}.md" (mkClaudeAgentContent name agent);
|
|
||||||
|
|
||||||
agentFiles = lib.mapAttrs mkClaudeAgentFile canonical;
|
|
||||||
|
|
||||||
# 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;
|
|
||||||
|
|
||||||
copyAgentCommands = lib.concatStringsSep "\n" (
|
|
||||||
lib.mapAttrsToList (name: file: "cp ${file} $out/.claude/agents/${name}.md") agentFiles
|
|
||||||
);
|
|
||||||
in
|
|
||||||
pkgs.runCommand "claude-code-agents" {} ''
|
|
||||||
mkdir -p $out/.claude/agents
|
|
||||||
${copyAgentCommands}
|
|
||||||
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,
|
|
||||||
}: let
|
|
||||||
# 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;
|
|
||||||
|
|
||||||
mkPiAgentFile = name: agent:
|
|
||||||
pkgs.writeText "${name}.md" (mkPiAgentContent name agent);
|
|
||||||
|
|
||||||
piAgentFiles = lib.mapAttrs mkPiAgentFile canonical;
|
|
||||||
|
|
||||||
# ── 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;
|
|
||||||
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"
|
|
||||||
);
|
|
||||||
|
|
||||||
agentsMdFile = pkgs.writeText "AGENTS.md" agentsMd;
|
|
||||||
systemMdFile = pkgs.writeText "SYSTEM.md" primary.systemPrompt;
|
|
||||||
|
|
||||||
copyAgentCommands = lib.concatStringsSep "\n" (
|
|
||||||
lib.mapAttrsToList (name: file: "cp ${file} $out/agents/${name}.md") piAgentFiles
|
|
||||||
);
|
|
||||||
in
|
|
||||||
pkgs.runCommand "pi-agents" {} ''
|
|
||||||
mkdir -p $out/agents
|
|
||||||
cp ${agentsMdFile} $out/AGENTS.md
|
|
||||||
cp ${systemMdFile} $out/SYSTEM.md
|
|
||||||
${copyAgentCommands}
|
|
||||||
'';
|
|
||||||
|
|
||||||
# ── renderForTool dispatcher ──────────────────────────────────
|
|
||||||
#
|
|
||||||
# Dispatches to the correct renderer by tool name.
|
|
||||||
# tool: "opencode" | "claude-code" | "pi"
|
|
||||||
|
|
||||||
renderForTool = {
|
|
||||||
pkgs,
|
|
||||||
agentsInput,
|
|
||||||
tool,
|
|
||||||
modelOverrides ? {},
|
|
||||||
}: 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;
|
|
||||||
}
|
|
||||||
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 ? {},
|
|
||||||
}: let
|
|
||||||
rendered = agentsLib.renderForTool {
|
|
||||||
inherit pkgs agentsInput tool modelOverrides;
|
|
||||||
};
|
|
||||||
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
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
# Opencode 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
|
|
||||||
# - An `opencode.json` file with a $schema reference and instructions list
|
|
||||||
#
|
|
||||||
# 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)
|
|
||||||
#
|
|
||||||
# Returns:
|
|
||||||
# An attribute set containing:
|
|
||||||
# - shellHook: Bash code to create symlink and opencode.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 ? [],
|
|
||||||
}: let
|
|
||||||
rulesDir = ".opencode-rules";
|
|
||||||
|
|
||||||
# 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 Opencode
|
|
||||||
opencodeConfig = {
|
|
||||||
"$schema" = "https://opencode.ai/config.json";
|
|
||||||
inherit instructions;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
inherit instructions;
|
|
||||||
|
|
||||||
# Shell hook to set up rules in the project
|
|
||||||
# Creates a symlink to the AGENTS rules directory and generates opencode.json
|
|
||||||
shellHook = ''
|
|
||||||
# Create/update symlink to AGENTS rules directory
|
|
||||||
ln -sfn ${agents}/rules ${rulesDir}
|
|
||||||
|
|
||||||
# Generate opencode.json configuration file
|
|
||||||
cat > opencode.json <<'OPENCODE_EOF'
|
|
||||||
${builtins.toJSON opencodeConfig}
|
|
||||||
OPENCODE_EOF
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# Backward-compat alias
|
|
||||||
mkOpencodeRules = mkCodingRules;
|
|
||||||
in {
|
|
||||||
inherit mkCodingRules mkOpencodeRules;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# 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 (renamed from opencode-rules)
|
|
||||||
coding-rules = import ./coding-rules.nix {inherit lib;};
|
|
||||||
|
|
||||||
# Backward-compat alias: opencode-rules → coding-rules
|
|
||||||
opencode-rules = import ./coding-rules.nix {inherit lib;};
|
|
||||||
|
|
||||||
# Agent configuration management utilities
|
|
||||||
agents = import ./agents.nix {inherit lib;};
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
# Opencode 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.opencode-rules.mkOpencodeRules {
|
|
||||||
# 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
|
|
||||||
# - An `opencode.json` file with a $schema reference and instructions list
|
|
||||||
#
|
|
||||||
# The instructions list contains paths relative to the project root, all prefixed
|
|
||||||
# with `.opencode-rules/`, making them portable across different project locations.
|
|
||||||
{lib}: {
|
|
||||||
# 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)
|
|
||||||
#
|
|
||||||
# Returns:
|
|
||||||
# An attribute set containing:
|
|
||||||
# - shellHook: Bash code to create symlink and opencode.json
|
|
||||||
# - instructions: List of rule file paths (relative to project root)
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# mkOpencodeRules {
|
|
||||||
# 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"
|
|
||||||
# # ];
|
|
||||||
# # }
|
|
||||||
mkOpencodeRules = {
|
|
||||||
agents,
|
|
||||||
languages ? [],
|
|
||||||
concerns ? [
|
|
||||||
"coding-style"
|
|
||||||
"naming"
|
|
||||||
"documentation"
|
|
||||||
"testing"
|
|
||||||
"git-workflow"
|
|
||||||
"project-structure"
|
|
||||||
],
|
|
||||||
frameworks ? [],
|
|
||||||
extraInstructions ? [],
|
|
||||||
}: let
|
|
||||||
rulesDir = ".opencode-rules";
|
|
||||||
|
|
||||||
# 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 Opencode
|
|
||||||
opencodeConfig = {
|
|
||||||
"$schema" = "https://opencode.ai/config.json";
|
|
||||||
inherit instructions;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
inherit instructions;
|
|
||||||
|
|
||||||
# Shell hook to set up rules in the project
|
|
||||||
# Creates a symlink to the AGENTS rules directory and generates opencode.json
|
|
||||||
shellHook = ''
|
|
||||||
# Create/update symlink to AGENTS rules directory
|
|
||||||
ln -sfn ${agents}/rules ${rulesDir}
|
|
||||||
|
|
||||||
# Generate opencode.json configuration file
|
|
||||||
cat > opencode.json <<'OPENCODE_EOF'
|
|
||||||
${builtins.toJSON opencodeConfig}
|
|
||||||
OPENCODE_EOF
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
-113
@@ -1,113 +0,0 @@
|
|||||||
# 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Simple helper to get a port without host override
|
|
||||||
# Useful when you don't need host-specific ports
|
|
||||||
#
|
|
||||||
# Args:
|
|
||||||
# portsConfig: Same structure as mkPortHelpers
|
|
||||||
# service: The service name (string)
|
|
||||||
#
|
|
||||||
# Returns:
|
|
||||||
# Port number (int) or null if service not found
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
# getDefaultPort myPorts "nginx" # Returns default port only
|
|
||||||
getDefaultPort = portsConfig: service:
|
|
||||||
portsConfig.ports.${service} or null;
|
|
||||||
}
|
|
||||||
@@ -1,238 +0,0 @@
|
|||||||
# 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 = {};
|
|
||||||
externalSkills = [{ src = inputs.skills-anthropic; }];
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options:** `enable`, `agentsInput`, `modelOverrides`, `externalSkills`
|
|
||||||
|
|
||||||
### Pi (`coding.agents.pi`)
|
|
||||||
|
|
||||||
Renders `AGENTS.md` + `SYSTEM.md` to `~/.pi/agent/` by default:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
coding.agents.pi = {
|
|
||||||
enable = true;
|
|
||||||
agentsInput = inputs.agents;
|
|
||||||
path = ".pi/agent"; # default, relative to $HOME
|
|
||||||
externalSkills = [{ src = inputs.skills-anthropic; }];
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Options:** `enable`, `path`, `agentsInput`, `modelOverrides`, `externalSkills`, `primaryAgent`, `mcpServers`, `settings`
|
|
||||||
|
|
||||||
### 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` (old name still works) |
|
|
||||||
|
|
||||||
### 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.
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# CLI/Terminal-related Home Manager modules
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./rofi-project-opener.nix
|
|
||||||
./stt-ptt.nix
|
|
||||||
./zellij-ps.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
{
|
|
||||||
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}"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
{
|
|
||||||
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
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
{
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.coding.agents.claude-code;
|
|
||||||
mcpCfg = config.programs.mcp or null;
|
|
||||||
in {
|
|
||||||
options.coding.agents.claude-code = {
|
|
||||||
enable = mkEnableOption "Claude Code agent management via canonical agent.toml definitions";
|
|
||||||
|
|
||||||
agentsInput = mkOption {
|
|
||||||
type = types.nullOr types.anything;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The `agents` flake input (your personal AGENTS repo).
|
|
||||||
When set, agents are rendered from canonical agent.toml files
|
|
||||||
and symlinked to ~/.claude/agents/.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
modelOverrides = mkOption {
|
|
||||||
type = types.attrsOf types.str;
|
|
||||||
default = {};
|
|
||||||
description = ''
|
|
||||||
Per-agent model overrides. Maps agent slug to model alias or ID.
|
|
||||||
Example: { chiron = "claude-sonnet-4-20250514"; }
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
{
|
|
||||||
chiron = "claude-sonnet-4-20250514";
|
|
||||||
"chiron-forge" = "claude-sonnet-4-20250514";
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
externalSkills = 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 mkOpencodeSkills.
|
|
||||||
Each entry maps directly to an element of the externalSkills
|
|
||||||
list accepted by the AGENTS flake's lib.mkOpencodeSkills.
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
[
|
|
||||||
{ src = inputs.skills-anthropic; selectSkills = [ "claude-api" ]; }
|
|
||||||
{ src = inputs.skills-vercel; }
|
|
||||||
]
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
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 = mkIf cfg.enable (let
|
|
||||||
agentsLib = (import ../../../../lib {inherit lib;}).agents;
|
|
||||||
|
|
||||||
# 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.mkOpencodeSkills {
|
|
||||||
inherit pkgs;
|
|
||||||
customSkills = "${cfg.agentsInput}/skills";
|
|
||||||
externalSkills =
|
|
||||||
map (
|
|
||||||
entry:
|
|
||||||
{inherit (entry) src skillsDir;}
|
|
||||||
// optionalAttrs (entry.selectSkills != null) {inherit (entry) selectSkills;}
|
|
||||||
)
|
|
||||||
cfg.externalSkills;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Rendered settings.json with permissions + MCP servers
|
|
||||||
home.file.".claude/settings.json" = mkIf (settingsJson != null) {
|
|
||||||
source = "${settingsJson}";
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# Per-tool agent sub-modules
|
|
||||||
# Each module handles rendering canonical agent.toml definitions
|
|
||||||
# for a specific AI coding tool.
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./opencode.nix
|
|
||||||
./claude-code.nix
|
|
||||||
./pi.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.coding.agents.opencode;
|
|
||||||
in {
|
|
||||||
options.coding.agents.opencode = {
|
|
||||||
enable = mkEnableOption "OpenCode agent management via canonical agent.toml definitions";
|
|
||||||
|
|
||||||
agentsInput = mkOption {
|
|
||||||
type = types.nullOr types.anything;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
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 = 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";
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
externalSkills = 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 mkOpencodeSkills.
|
|
||||||
Each entry maps directly to an element of the externalSkills
|
|
||||||
list accepted by the AGENTS flake's lib.mkOpencodeSkills.
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
[
|
|
||||||
{ src = inputs.skills-anthropic; selectSkills = [ "claude-api" ]; }
|
|
||||||
{ src = inputs.skills-vercel; }
|
|
||||||
]
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
# Rendered agent files symlinked to ~/.config/opencode/agents/
|
|
||||||
xdg.configFile."opencode/agents" = mkIf (cfg.agentsInput != null) {
|
|
||||||
source = (import ../../../../lib {inherit lib;}).agents.renderForOpencode {
|
|
||||||
inherit pkgs;
|
|
||||||
canonical = cfg.agentsInput.lib.loadAgents;
|
|
||||||
modelOverrides = cfg.modelOverrides;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Skills (merged from personal AGENTS repo + optional external skills)
|
|
||||||
xdg.configFile."opencode/skills" = mkIf (cfg.agentsInput != null) {
|
|
||||||
source = cfg.agentsInput.lib.mkOpencodeSkills {
|
|
||||||
inherit pkgs;
|
|
||||||
customSkills = "${cfg.agentsInput}/skills";
|
|
||||||
externalSkills =
|
|
||||||
map (
|
|
||||||
entry:
|
|
||||||
{inherit (entry) src skillsDir;}
|
|
||||||
// optionalAttrs (entry.selectSkills != null) {inherit (entry) selectSkills;}
|
|
||||||
)
|
|
||||||
cfg.externalSkills;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# 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";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,298 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.coding.agents.pi;
|
|
||||||
mcpCfg = config.programs.mcp or null;
|
|
||||||
in {
|
|
||||||
options.coding.agents.pi = {
|
|
||||||
enable = mkEnableOption "Pi agent management via canonical agent.toml definitions";
|
|
||||||
|
|
||||||
path = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = ".pi/agent";
|
|
||||||
description = ''
|
|
||||||
Relative path (inside the Home Manager user's home) where Pi agent
|
|
||||||
config should be materialized.
|
|
||||||
|
|
||||||
Defaults to `.pi/agent`, i.e. `~/.pi/agent`.
|
|
||||||
'';
|
|
||||||
example = ".config/pi/agent";
|
|
||||||
};
|
|
||||||
|
|
||||||
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 `${cfg.path}/mcp.json`.
|
|
||||||
Automatically inherits from config.programs.mcp.servers.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
agentsInput = mkOption {
|
|
||||||
type = types.nullOr types.anything;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
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 = mkOption {
|
|
||||||
type = types.attrsOf types.str;
|
|
||||||
default = {};
|
|
||||||
description = ''
|
|
||||||
Per-agent model overrides for Pi subagents.
|
|
||||||
Maps agent slug to model string, e.g.:
|
|
||||||
{ chiron = "anthropic/claude-sonnet-4"; chiron-forge = "anthropic/claude-sonnet-4"; }
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
externalSkills = 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 mkOpencodeSkills.
|
|
||||||
Each entry maps directly to an element of the externalSkills
|
|
||||||
list accepted by the AGENTS flake's lib.mkOpencodeSkills.
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
[
|
|
||||||
{ src = inputs.skills-anthropic; selectSkills = [ "claude-api" ]; }
|
|
||||||
{ src = inputs.skills-vercel; }
|
|
||||||
]
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
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.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
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 `${cfg.path}/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 `${cfg.path}/settings.json`.
|
|
||||||
Only non-null values are included in the generated JSON.
|
|
||||||
See pi docs/settings.md for all options.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable (let
|
|
||||||
basePath = lib.removeSuffix "/" cfg.path;
|
|
||||||
|
|
||||||
# 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
|
|
||||||
);
|
|
||||||
|
|
||||||
piSettings = filterNulls cfg.settings;
|
|
||||||
|
|
||||||
# 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;
|
|
||||||
}
|
|
||||||
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 = "${basePath}/agents/${name}.md";
|
|
||||||
value = {source = "${rendered}/agents/${name}.md";};
|
|
||||||
})
|
|
||||||
agentNames
|
|
||||||
)
|
|
||||||
else {};
|
|
||||||
in {
|
|
||||||
home.file = mkMerge [
|
|
||||||
# ── MCP servers from programs.mcp → ${cfg.path}/mcp.json ───────
|
|
||||||
(mkIf (cfg.mcpServers != {}) {
|
|
||||||
"${basePath}/mcp.json".text = builtins.toJSON {mcpServers = cfg.mcpServers;};
|
|
||||||
})
|
|
||||||
|
|
||||||
# ── ${cfg.path}/settings.json ──────────────────────────────────
|
|
||||||
{
|
|
||||||
"${basePath}/settings.json".text = builtins.toJSON piSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
# ── AGENTS.md — agent descriptions and specialist listing ──────
|
|
||||||
(mkIf (cfg.agentsInput != null) {
|
|
||||||
"${basePath}/AGENTS.md".source = "${rendered}/AGENTS.md";
|
|
||||||
})
|
|
||||||
|
|
||||||
# ── SYSTEM.md — primary agent's system prompt ──────────────────
|
|
||||||
(mkIf (cfg.agentsInput != null) {
|
|
||||||
"${basePath}/SYSTEM.md".source = "${rendered}/SYSTEM.md";
|
|
||||||
})
|
|
||||||
|
|
||||||
# ── Agents — pi-subagents .md files ────────────────────────────
|
|
||||||
agentFiles
|
|
||||||
|
|
||||||
# ── Skills symlinked from AGENTS repo ──────────────────────────
|
|
||||||
(mkIf (cfg.agentsInput != null) {
|
|
||||||
"${basePath}/skills".source = cfg.agentsInput.lib.mkOpencodeSkills {
|
|
||||||
inherit pkgs;
|
|
||||||
customSkills = "${cfg.agentsInput}/skills";
|
|
||||||
externalSkills =
|
|
||||||
map (
|
|
||||||
entry:
|
|
||||||
{inherit (entry) src skillsDir;}
|
|
||||||
// optionalAttrs (entry.selectSkills != null) {inherit (entry) selectSkills;}
|
|
||||||
)
|
|
||||||
cfg.externalSkills;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# Coding-related Home Manager modules
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./editors.nix
|
|
||||||
./opencode.nix
|
|
||||||
./agents
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
{
|
|
||||||
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 = {
|
|
||||||
# UI and Theme
|
|
||||||
theme = "Dracula";
|
|
||||||
ui_font_size = 16;
|
|
||||||
buffer_font_size = 16;
|
|
||||||
buffer_font_family = "FiraCode Nerd Font";
|
|
||||||
# Editor Behavior
|
|
||||||
vim_mode = true;
|
|
||||||
auto_update = false;
|
|
||||||
format_on_save = "on";
|
|
||||||
load_direnv = "shell_hook";
|
|
||||||
# AI Features
|
|
||||||
features = {
|
|
||||||
edit_prediction_provider = "zed";
|
|
||||||
};
|
|
||||||
edit_predictions = {
|
|
||||||
mode = "subtle";
|
|
||||||
};
|
|
||||||
show_edit_predictions = true;
|
|
||||||
agent = {
|
|
||||||
default_model = {
|
|
||||||
provider = "zed.dev";
|
|
||||||
model = "claude-sonnet-4";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
assistant = {
|
|
||||||
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";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
pyrefly = {
|
|
||||||
binary = {
|
|
||||||
arguments = ["--lsp"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
# Context Servers
|
|
||||||
context_servers = {
|
|
||||||
some-context-server = {
|
|
||||||
source = "custom";
|
|
||||||
command = "some-command";
|
|
||||||
args = [
|
|
||||||
"arg-1"
|
|
||||||
"arg-2"
|
|
||||||
];
|
|
||||||
env = {};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
# Privacy
|
|
||||||
telemetry = {
|
|
||||||
metrics = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
# Common packages (always installed if either editor is enabled)
|
|
||||||
(mkIf (cfg.neovim.enable || cfg.zed.enable) {
|
|
||||||
home.packages = with pkgs; [zig];
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
{
|
|
||||||
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
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# Home Manager modules organized by category
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./cli
|
|
||||||
./coding
|
|
||||||
./ports.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
# 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;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# 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
|
|
||||||
./pi-agent.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
|
|
||||||
# };
|
|
||||||
}
|
|
||||||
@@ -1,363 +0,0 @@
|
|||||||
# 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];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,748 +0,0 @@
|
|||||||
# NixOS Module for isolated Pi execution (fresh design)
|
|
||||||
#
|
|
||||||
# Goals:
|
|
||||||
# - Dedicated isolated runtime identity (pi-agent user/group)
|
|
||||||
# - Host UX via `pi` wrapper command
|
|
||||||
# - Per-host-user project allowlists (different roots per user)
|
|
||||||
# - No container mode
|
|
||||||
# - Merge user Pi config + Nix-managed settings/env into isolated runtime
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.m3ta.pi-agent;
|
|
||||||
|
|
||||||
hostUserNames = attrNames cfg.hostUsers;
|
|
||||||
|
|
||||||
managedSettingsFile = pkgs.writeText "pi-agent-managed-settings.json" (builtins.toJSON cfg.settings);
|
|
||||||
|
|
||||||
managedEnvFile =
|
|
||||||
pkgs.writeText "pi-agent-managed.env"
|
|
||||||
(concatStringsSep "\n" (mapAttrsToList (k: v: "${k}=${v}") cfg.environment));
|
|
||||||
|
|
||||||
runtimePath = concatStringsSep ":" (
|
|
||||||
[
|
|
||||||
"${cfg.package}/bin"
|
|
||||||
"${pkgs.nodejs}/bin"
|
|
||||||
"${pkgs.git}/bin"
|
|
||||||
"${pkgs.coreutils}/bin"
|
|
||||||
"${pkgs.findutils}/bin"
|
|
||||||
"${pkgs.gnugrep}/bin"
|
|
||||||
"${pkgs.gnused}/bin"
|
|
||||||
"${pkgs.util-linux}/bin"
|
|
||||||
"/run/current-system/sw/bin"
|
|
||||||
]
|
|
||||||
++ map (p: "${p}/bin") cfg.extraPackages
|
|
||||||
);
|
|
||||||
|
|
||||||
userPolicyCase = concatStringsSep "\n" (
|
|
||||||
mapAttrsToList (
|
|
||||||
user: userCfg: ''
|
|
||||||
${escapeShellArg user})
|
|
||||||
USER_CONFIG_PATH=${escapeShellArg (
|
|
||||||
if userCfg.configPath != null
|
|
||||||
then userCfg.configPath
|
|
||||||
else cfg.wrapper.hostConfigPath
|
|
||||||
)}
|
|
||||||
USER_ROOTS=(${concatStringsSep " " (map escapeShellArg userCfg.projectRoots)})
|
|
||||||
;;
|
|
||||||
''
|
|
||||||
)
|
|
||||||
cfg.hostUsers
|
|
||||||
);
|
|
||||||
|
|
||||||
runner = pkgs.writeShellScriptBin cfg.wrapper.runnerName ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
|
||||||
echo "${cfg.wrapper.runnerName} must run as root" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$#" -lt 2 ]; then
|
|
||||||
echo "Usage: ${cfg.wrapper.runnerName} <invoking-user> <cwd> [pi-args...]" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
invoking_user="$1"
|
|
||||||
shift
|
|
||||||
cwd="$1"
|
|
||||||
shift
|
|
||||||
|
|
||||||
resolve_user_policy() {
|
|
||||||
local user="$1"
|
|
||||||
USER_CONFIG_PATH=""
|
|
||||||
USER_ROOTS=()
|
|
||||||
case "$user" in
|
|
||||||
${userPolicyCase}
|
|
||||||
*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! resolve_user_policy "$invoking_user"; then
|
|
||||||
echo "User '$invoking_user' is not allowed to use ${cfg.wrapper.commandName}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
user_home="$(eval echo "~$invoking_user")"
|
|
||||||
if [ -z "$user_home" ] || [ "$user_home" = "~$invoking_user" ]; then
|
|
||||||
echo "Unable to determine home directory for user '$invoking_user'" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
expand_home_path() {
|
|
||||||
local input="$1"
|
|
||||||
if [ "$input" = "~" ]; then
|
|
||||||
printf '%s\n' "$user_home"
|
|
||||||
elif ${pkgs.gnugrep}/bin/grep -q '^~/' <<<"$input"; then
|
|
||||||
printf '%s\n' "$user_home/''${input:2}"
|
|
||||||
elif ${pkgs.gnugrep}/bin/grep -q '^/' <<<"$input"; then
|
|
||||||
printf '%s\n' "$input"
|
|
||||||
else
|
|
||||||
# Bare relative path → resolve from user's home
|
|
||||||
printf '%s\n' "$user_home/$input"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
cwd_real="$(${pkgs.coreutils}/bin/realpath -m "$cwd")"
|
|
||||||
|
|
||||||
resolved_roots=()
|
|
||||||
skipped_roots=()
|
|
||||||
is_allowed_cwd=0
|
|
||||||
for configured_root in "''${USER_ROOTS[@]}"; do
|
|
||||||
expanded_root="$(expand_home_path "$configured_root")"
|
|
||||||
resolved_root="$(${pkgs.coreutils}/bin/realpath -m "$expanded_root")"
|
|
||||||
if [ ! -d "$resolved_root" ]; then
|
|
||||||
skipped_roots+=("$resolved_root")
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
resolved_roots+=("$resolved_root")
|
|
||||||
case "$cwd_real/" in
|
|
||||||
"$resolved_root"/*)
|
|
||||||
is_allowed_cwd=1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "''${#resolved_roots[@]}" -eq 0 ]; then
|
|
||||||
echo "Denied: no valid existing project roots are configured for user '$invoking_user'." >&2
|
|
||||||
if [ "''${#skipped_roots[@]}" -gt 0 ]; then
|
|
||||||
echo "Configured but missing roots:" >&2
|
|
||||||
for root in "''${skipped_roots[@]}"; do
|
|
||||||
echo " - $root" >&2
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$is_allowed_cwd" -ne 1 ]; then
|
|
||||||
echo "Denied: '$cwd_real' is outside allowed project roots for user '$invoking_user'." >&2
|
|
||||||
echo "Allowed roots:" >&2
|
|
||||||
for root in "''${resolved_roots[@]}"; do
|
|
||||||
echo " - $root" >&2
|
|
||||||
done
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
${pkgs.coreutils}/bin/install -d -m 0750 -o ${escapeShellArg cfg.user} -g ${escapeShellArg cfg.group} \
|
|
||||||
${escapeShellArg cfg.stateDir} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/.pi"} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/.pi/agent"} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/.pi/agent/sessions"} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/.project-mounts"} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/projects"} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/.npm"} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/.npm-global"} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/.npm-global/bin"} \
|
|
||||||
${escapeShellArg "${cfg.stateDir}/.npm-global/lib"}
|
|
||||||
|
|
||||||
config_source="$USER_CONFIG_PATH"
|
|
||||||
if ${pkgs.gnugrep}/bin/grep -q '^/' <<<"$config_source"; then
|
|
||||||
source_dir="$config_source"
|
|
||||||
else
|
|
||||||
source_dir="$(expand_home_path "$config_source")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
if [ "${
|
|
||||||
if cfg.wrapper.syncConfigFromHost
|
|
||||||
then "1"
|
|
||||||
else "0"
|
|
||||||
}" = "1" ] && [ -d "$source_dir" ]; then
|
|
||||||
${pkgs.rsync}/bin/rsync -a --delete \
|
|
||||||
--exclude='auth.json' \
|
|
||||||
--exclude='mcp-oauth' \
|
|
||||||
--exclude='sessions' \
|
|
||||||
--exclude='bin' \
|
|
||||||
--exclude='mcp-cache.json' \
|
|
||||||
"$source_dir/" ${escapeShellArg "${cfg.stateDir}/.pi/agent/"}
|
|
||||||
${pkgs.coreutils}/bin/chown -R ${escapeShellArg "${cfg.user}:${cfg.group}"} ${escapeShellArg "${cfg.stateDir}/.pi/agent"}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Merge host settings.json (if any) with Nix-managed settings.
|
|
||||||
# Precedence: host settings first, Nix-managed keys override recursively.
|
|
||||||
settings_target=${escapeShellArg "${cfg.stateDir}/.pi/agent/settings.json"}
|
|
||||||
${pkgs.python3}/bin/python3 - "$settings_target" ${escapeShellArg managedSettingsFile} <<'PY_PI_SETTINGS_MERGE'
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def load_obj(path):
|
|
||||||
if not os.path.exists(path):
|
|
||||||
return {}
|
|
||||||
try:
|
|
||||||
with open(path, "r", encoding="utf-8") as f:
|
|
||||||
data = json.load(f)
|
|
||||||
return data if isinstance(data, dict) else {}
|
|
||||||
except Exception:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def deep_merge(base, override):
|
|
||||||
if isinstance(base, dict) and isinstance(override, dict):
|
|
||||||
out = dict(base)
|
|
||||||
for key, value in override.items():
|
|
||||||
out[key] = deep_merge(out.get(key), value)
|
|
||||||
return out
|
|
||||||
return override
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
target = sys.argv[1]
|
|
||||||
managed = sys.argv[2]
|
|
||||||
base_obj = load_obj(target)
|
|
||||||
managed_obj = load_obj(managed)
|
|
||||||
merged = deep_merge(base_obj, managed_obj)
|
|
||||||
|
|
||||||
os.makedirs(os.path.dirname(target), exist_ok=True)
|
|
||||||
tmp = f"{target}.tmp"
|
|
||||||
with open(tmp, "w", encoding="utf-8") as f:
|
|
||||||
json.dump(merged, f, indent=2, sort_keys=True)
|
|
||||||
f.write("\n")
|
|
||||||
os.replace(tmp, target)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
PY_PI_SETTINGS_MERGE
|
|
||||||
${pkgs.coreutils}/bin/chown ${escapeShellArg "${cfg.user}:${cfg.group}"} "$settings_target"
|
|
||||||
${pkgs.coreutils}/bin/chmod 0640 "$settings_target"
|
|
||||||
|
|
||||||
# Merge environment into isolated .env with precedence:
|
|
||||||
# 1) synced host env (source_dir/.env)
|
|
||||||
# 2) Nix-managed environment attrset
|
|
||||||
# 3) Nix-managed environmentFiles (appended in declaration order)
|
|
||||||
env_target=${escapeShellArg "${cfg.stateDir}/.pi/.env"}
|
|
||||||
${pkgs.coreutils}/bin/install -o ${escapeShellArg cfg.user} -g ${escapeShellArg cfg.group} -m 0640 /dev/null "$env_target"
|
|
||||||
|
|
||||||
if [ -f "$source_dir/.env" ]; then
|
|
||||||
${pkgs.coreutils}/bin/cat "$source_dir/.env" >> "$env_target"
|
|
||||||
printf '\n' >> "$env_target"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f ${escapeShellArg managedEnvFile} ]; then
|
|
||||||
${pkgs.coreutils}/bin/cat ${escapeShellArg managedEnvFile} >> "$env_target"
|
|
||||||
printf '\n' >> "$env_target"
|
|
||||||
fi
|
|
||||||
|
|
||||||
${concatStringsSep "\n" (map (f: ''
|
|
||||||
if [ -f ${escapeShellArg f} ]; then
|
|
||||||
${pkgs.coreutils}/bin/cat ${escapeShellArg f} >> "$env_target"
|
|
||||||
printf '\n' >> "$env_target"
|
|
||||||
fi
|
|
||||||
'')
|
|
||||||
cfg.environmentFiles)}
|
|
||||||
|
|
||||||
${pkgs.coreutils}/bin/chown ${escapeShellArg "${cfg.user}:${cfg.group}"} "$env_target"
|
|
||||||
${pkgs.coreutils}/bin/chmod 0640 "$env_target"
|
|
||||||
|
|
||||||
npm_prefix=${escapeShellArg "${cfg.stateDir}/.npm-global"}
|
|
||||||
runtime_path=${escapeShellArg runtimePath}
|
|
||||||
|
|
||||||
project_mount_dir=${escapeShellArg "${cfg.stateDir}/.project-mounts"}
|
|
||||||
project_links_dir=${escapeShellArg "${cfg.stateDir}/projects"}
|
|
||||||
project_bind_pairs=()
|
|
||||||
|
|
||||||
matched_root=""
|
|
||||||
matched_mount=""
|
|
||||||
project_index=0
|
|
||||||
|
|
||||||
for root in "''${resolved_roots[@]}"; do
|
|
||||||
if [ ! -d "$root" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
root_slug="$(printf '%s' "$root" | ${pkgs.gnused}/bin/sed 's#^/##; s#/#-#g; s#-\{2,\}#-#g; s#-$##; s#^$#root#')"
|
|
||||||
root_slug="''${project_index}-''${root_slug}"
|
|
||||||
project_index=$((project_index + 1))
|
|
||||||
|
|
||||||
mount_point="''${project_mount_dir}/''${root_slug}"
|
|
||||||
link_path="''${project_links_dir}/''${root_slug}"
|
|
||||||
|
|
||||||
${pkgs.coreutils}/bin/install -d -m 0750 -o ${escapeShellArg cfg.user} -g ${escapeShellArg cfg.group} "$mount_point"
|
|
||||||
${pkgs.coreutils}/bin/ln -sfn "$mount_point" "$link_path"
|
|
||||||
|
|
||||||
project_bind_pairs+=("$root:$mount_point")
|
|
||||||
|
|
||||||
case "$cwd_real/" in
|
|
||||||
"$root"/*)
|
|
||||||
if [ -z "$matched_root" ] || [ "''${#root}" -gt "''${#matched_root}" ]; then
|
|
||||||
matched_root="$root"
|
|
||||||
matched_mount="$mount_point"
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -z "$matched_root" ]; then
|
|
||||||
echo "Failed to map cwd '$cwd_real' to an allowed root." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$cwd_real" = "$matched_root" ]; then
|
|
||||||
mapped_cwd="$matched_mount"
|
|
||||||
else
|
|
||||||
rel_path="''${cwd_real#"$matched_root/"}"
|
|
||||||
mapped_cwd="$matched_mount/$rel_path"
|
|
||||||
fi
|
|
||||||
|
|
||||||
pi_bin=${escapeShellArg "${cfg.package}/bin/${cfg.binaryName}"}
|
|
||||||
|
|
||||||
if [ ! -x "$pi_bin" ]; then
|
|
||||||
for candidate in pi pi-agent; do
|
|
||||||
alt=${escapeShellArg "${cfg.package}/bin"}/$candidate
|
|
||||||
if [ -x "$alt" ]; then
|
|
||||||
pi_bin="$alt"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -x "$pi_bin" ]; then
|
|
||||||
echo "Pi binary not found or not executable: $pi_bin" >&2
|
|
||||||
echo "Available executables in ${cfg.package}/bin:" >&2
|
|
||||||
${pkgs.coreutils}/bin/ls -1 ${escapeShellArg "${cfg.package}/bin"} >&2 || true
|
|
||||||
exit 127
|
|
||||||
fi
|
|
||||||
|
|
||||||
cmd=(
|
|
||||||
${pkgs.systemd}/bin/systemd-run
|
|
||||||
--collect
|
|
||||||
--wait
|
|
||||||
--pty
|
|
||||||
--service-type=exec
|
|
||||||
-p User=${cfg.user}
|
|
||||||
-p Group=${cfg.group}
|
|
||||||
-p WorkingDirectory="$mapped_cwd"
|
|
||||||
-p NoNewPrivileges=yes
|
|
||||||
-p PrivateTmp=yes
|
|
||||||
-p ProtectSystem=strict
|
|
||||||
-p ProtectHome=false
|
|
||||||
-p ProtectControlGroups=yes
|
|
||||||
-p ProtectKernelTunables=yes
|
|
||||||
-p ProtectKernelModules=yes
|
|
||||||
-p RestrictSUIDSGID=yes
|
|
||||||
-p LockPersonality=yes
|
|
||||||
-p RestrictRealtime=yes
|
|
||||||
-p RestrictNamespaces=yes
|
|
||||||
-p MemoryDenyWriteExecute=no
|
|
||||||
-p UMask=0007
|
|
||||||
-p ReadWritePaths=${cfg.stateDir}
|
|
||||||
-p EnvironmentFile=${cfg.stateDir}/.pi/.env
|
|
||||||
-E HOME=${cfg.stateDir}
|
|
||||||
-E PI_HOME=${cfg.stateDir}/.pi
|
|
||||||
-E MESSAGING_CWD="$mapped_cwd"
|
|
||||||
-E PATH="$runtime_path"
|
|
||||||
-E NPM_CONFIG_CACHE=${cfg.stateDir}/.npm
|
|
||||||
-E NPM_CONFIG_PREFIX="$npm_prefix"
|
|
||||||
-E PI_AGENT_INVOKING_USER="$invoking_user"
|
|
||||||
)
|
|
||||||
|
|
||||||
${optionalString (cfg.projectGroup != null) ''
|
|
||||||
cmd+=( -p SupplementaryGroups=${cfg.projectGroup} )
|
|
||||||
''}
|
|
||||||
|
|
||||||
# Only mark existing top-level paths inaccessible; systemd fails namespace
|
|
||||||
# setup if InaccessiblePaths points to a non-existent path on this host.
|
|
||||||
for p in /home /root /mnt /media /srv; do
|
|
||||||
if [ -e "$p" ]; then
|
|
||||||
cmd+=( -p "InaccessiblePaths=$p" )
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
for pair in "''${project_bind_pairs[@]}"; do
|
|
||||||
src="''${pair%%:*}"
|
|
||||||
dst="''${pair#*:}"
|
|
||||||
cmd+=( -p "BindPaths=$src:$dst" )
|
|
||||||
done
|
|
||||||
|
|
||||||
${concatStringsSep "\n" (mapAttrsToList (name: value: ''cmd+=( -E ${escapeShellArg "${name}=${value}"} )'') cfg.wrapper.extraEnvironment)}
|
|
||||||
|
|
||||||
cmd+=( "$pi_bin" )
|
|
||||||
${concatStringsSep "\n" (map (arg: ''cmd+=( ${escapeShellArg arg} )'') cfg.wrapper.extraRunArgs)}
|
|
||||||
cmd+=( "$@" )
|
|
||||||
|
|
||||||
exec "''${cmd[@]}"
|
|
||||||
'';
|
|
||||||
|
|
||||||
wrapper = pkgs.writeShellScriptBin cfg.wrapper.commandName ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
user_name="$(id -un)"
|
|
||||||
user_home="$(eval echo "~$user_name")"
|
|
||||||
if [ -z "$user_home" ] || [ "$user_home" = "~$user_name" ]; then
|
|
||||||
user_home="$HOME"
|
|
||||||
fi
|
|
||||||
|
|
||||||
resolve_user_policy() {
|
|
||||||
local user="$1"
|
|
||||||
USER_ROOTS=()
|
|
||||||
case "$user" in
|
|
||||||
${concatStringsSep "\n" (
|
|
||||||
mapAttrsToList (
|
|
||||||
user: userCfg: ''
|
|
||||||
${escapeShellArg user})
|
|
||||||
USER_ROOTS=(${concatStringsSep " " (map escapeShellArg userCfg.projectRoots)})
|
|
||||||
;;
|
|
||||||
''
|
|
||||||
)
|
|
||||||
cfg.hostUsers
|
|
||||||
)}
|
|
||||||
*)
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! resolve_user_policy "$user_name"; then
|
|
||||||
echo "User '$user_name' is not allowed to use ${cfg.wrapper.commandName}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
expand_home_path() {
|
|
||||||
local input="$1"
|
|
||||||
if [ "$input" = "~" ]; then
|
|
||||||
printf '%s\n' "$user_home"
|
|
||||||
elif ${pkgs.gnugrep}/bin/grep -q '^~/' <<<"$input"; then
|
|
||||||
printf '%s\n' "$user_home/''${input:2}"
|
|
||||||
elif ${pkgs.gnugrep}/bin/grep -q '^/' <<<"$input"; then
|
|
||||||
printf '%s\n' "$input"
|
|
||||||
else
|
|
||||||
printf '%s\n' "$user_home/$input"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
cwd_real="$(${pkgs.coreutils}/bin/realpath -m "$PWD")"
|
|
||||||
|
|
||||||
is_allowed_cwd=0
|
|
||||||
resolved_roots=()
|
|
||||||
skipped_roots=()
|
|
||||||
for configured_root in "''${USER_ROOTS[@]}"; do
|
|
||||||
expanded_root="$(expand_home_path "$configured_root")"
|
|
||||||
resolved_root="$(${pkgs.coreutils}/bin/realpath -m "$expanded_root")"
|
|
||||||
if [ ! -d "$resolved_root" ]; then
|
|
||||||
skipped_roots+=("$resolved_root")
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
resolved_roots+=("$resolved_root")
|
|
||||||
case "$cwd_real/" in
|
|
||||||
"$resolved_root"/*)
|
|
||||||
is_allowed_cwd=1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "''${#resolved_roots[@]}" -eq 0 ]; then
|
|
||||||
echo "Denied: no valid existing project roots are configured for user '$user_name'." >&2
|
|
||||||
if [ "''${#skipped_roots[@]}" -gt 0 ]; then
|
|
||||||
echo "Configured but missing roots:" >&2
|
|
||||||
for root in "''${skipped_roots[@]}"; do
|
|
||||||
echo " - $root" >&2
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$is_allowed_cwd" -ne 1 ]; then
|
|
||||||
echo "Denied: '$cwd_real' is outside allowed project roots for user '$user_name'." >&2
|
|
||||||
echo "Allowed roots:" >&2
|
|
||||||
for root in "''${resolved_roots[@]}"; do
|
|
||||||
echo " - $root" >&2
|
|
||||||
done
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec /run/wrappers/bin/sudo --non-interactive ${runner}/bin/${cfg.wrapper.runnerName} "$user_name" "$cwd_real" "$@"
|
|
||||||
'';
|
|
||||||
in {
|
|
||||||
options.m3ta.pi-agent = {
|
|
||||||
enable = mkEnableOption "isolated Pi execution with dedicated system user and policy-enforced wrapper";
|
|
||||||
|
|
||||||
package = mkOption {
|
|
||||||
type = types.package;
|
|
||||||
default = pkgs.pi-coding-agent;
|
|
||||||
defaultText = literalExpression "pkgs.pi-coding-agent";
|
|
||||||
description = "Pi package providing the executable used in isolated runtime.";
|
|
||||||
};
|
|
||||||
|
|
||||||
binaryName = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "pi-agent";
|
|
||||||
description = "Preferred executable name inside `${cfg.package}/bin` (falls back to pi/pi-agent auto-detection).";
|
|
||||||
example = "pi";
|
|
||||||
};
|
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "pi-agent";
|
|
||||||
description = "System user that executes Pi in isolated mode.";
|
|
||||||
};
|
|
||||||
|
|
||||||
group = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "pi-agent";
|
|
||||||
description = "System group for the isolated Pi user.";
|
|
||||||
};
|
|
||||||
|
|
||||||
stateDir = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "/var/lib/pi-agent";
|
|
||||||
description = "Writable state/home directory for isolated Pi runtime.";
|
|
||||||
};
|
|
||||||
|
|
||||||
createUser = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = "Whether to create the dedicated Pi user/group automatically.";
|
|
||||||
};
|
|
||||||
|
|
||||||
hostUsers = mkOption {
|
|
||||||
type = types.attrsOf (types.submodule {
|
|
||||||
options = {
|
|
||||||
projectRoots = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = ''
|
|
||||||
Allowed project roots for this host user.
|
|
||||||
`~` and `~/...` are expanded relative to that host user's home.
|
|
||||||
'';
|
|
||||||
example = ["~/p" "~/work/client-a"];
|
|
||||||
};
|
|
||||||
|
|
||||||
configPath = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Optional host path for this user's Pi config source. If null,
|
|
||||||
wrapper.hostConfigPath is used. Relative paths resolve from the
|
|
||||||
host user's home.
|
|
||||||
'';
|
|
||||||
example = ".pi/agent";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
});
|
|
||||||
default = {};
|
|
||||||
description = ''
|
|
||||||
Per-host-user policy map. Keys are host usernames.
|
|
||||||
Each user defines their own allowed project roots and optional config source.
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
{
|
|
||||||
m3tam3re = {
|
|
||||||
projectRoots = [ "~/p" "~/src/private" ];
|
|
||||||
configPath = ".pi/agent";
|
|
||||||
};
|
|
||||||
teammate = {
|
|
||||||
projectRoots = [ "~/projects" ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
settings = mkOption {
|
|
||||||
type = types.attrsOf types.anything;
|
|
||||||
default = {};
|
|
||||||
description = ''
|
|
||||||
Nix-managed Pi settings merged into isolated `${cfg.stateDir}/.pi/agent/settings.json`.
|
|
||||||
Merge precedence: synced host settings first, Nix-managed values override recursively.
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
{
|
|
||||||
defaultModel = "anthropic/claude-sonnet-4";
|
|
||||||
defaultProvider = "anthropic";
|
|
||||||
quietStartup = true;
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
environment = mkOption {
|
|
||||||
type = types.attrsOf types.str;
|
|
||||||
default = {};
|
|
||||||
description = ''
|
|
||||||
Non-secret Nix-managed environment variables appended into isolated
|
|
||||||
`${cfg.stateDir}/.pi/.env` after synced host values.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
environmentFiles = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = ''
|
|
||||||
Paths to env files (secrets/tokens) appended to isolated `${cfg.stateDir}/.pi/.env`
|
|
||||||
after `environment` entries.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extraPackages = mkOption {
|
|
||||||
type = types.listOf types.package;
|
|
||||||
default = [];
|
|
||||||
description = "Extra packages added to isolated runtime PATH.";
|
|
||||||
};
|
|
||||||
|
|
||||||
projectGroup = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
When set, the pi-agent user is added to this group and the group is
|
|
||||||
passed as SupplementaryGroups to the systemd-run sandbox. This allows
|
|
||||||
pi-agent to write to project directories that grant group write access.
|
|
||||||
The user must ensure project directories have appropriate group ownership
|
|
||||||
and permissions (e.g. setgid + group write).
|
|
||||||
'';
|
|
||||||
example = "users";
|
|
||||||
};
|
|
||||||
|
|
||||||
wrapper = {
|
|
||||||
enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = "Enable host-side wrapper command that enforces policy and runs isolated Pi.";
|
|
||||||
};
|
|
||||||
|
|
||||||
commandName = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "pi";
|
|
||||||
description = "Host wrapper command name.";
|
|
||||||
};
|
|
||||||
|
|
||||||
runnerName = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "m3ta-pi-agent-runner";
|
|
||||||
description = "Privileged runner command invoked via scoped sudo rule.";
|
|
||||||
};
|
|
||||||
|
|
||||||
hideDirectBinary = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = ''
|
|
||||||
When true and wrapper is enabled, do not add the raw Pi package to host PATH,
|
|
||||||
reducing bypass risk by making wrapper the canonical entrypoint.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
syncConfigFromHost = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = ''
|
|
||||||
Sync host Pi config directory into isolated `${cfg.stateDir}/.pi/agent`
|
|
||||||
on each invocation.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
hostConfigPath = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = ".pi/agent";
|
|
||||||
description = ''
|
|
||||||
Default source path for host Pi config sync. Relative paths resolve from
|
|
||||||
the invoking user's home. Per-user hostUsers.<name>.configPath overrides this.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extraRunArgs = mkOption {
|
|
||||||
type = types.listOf types.str;
|
|
||||||
default = [];
|
|
||||||
description = "Extra arguments inserted before user-provided Pi args.";
|
|
||||||
};
|
|
||||||
|
|
||||||
extraEnvironment = mkOption {
|
|
||||||
type = types.attrsOf types.str;
|
|
||||||
default = {};
|
|
||||||
description = "Additional environment variables passed to isolated Pi runtime.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
assertions =
|
|
||||||
[
|
|
||||||
{
|
|
||||||
assertion = cfg.hostUsers != {};
|
|
||||||
message = "m3ta.pi-agent.hostUsers must define at least one authorized host user.";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = (!cfg.wrapper.enable) || (cfg.hostUsers != {});
|
|
||||||
message = "m3ta.pi-agent.hostUsers must not be empty when wrapper is enabled.";
|
|
||||||
}
|
|
||||||
]
|
|
||||||
++ mapAttrsToList (user: userCfg: {
|
|
||||||
assertion = userCfg.projectRoots != [];
|
|
||||||
message = "m3ta.pi-agent.hostUsers.${user}.projectRoots must not be empty.";
|
|
||||||
})
|
|
||||||
cfg.hostUsers;
|
|
||||||
|
|
||||||
users.groups = mkIf cfg.createUser {
|
|
||||||
"${cfg.group}" = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
users.users = mkIf cfg.createUser {
|
|
||||||
"${cfg.user}" = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = cfg.group;
|
|
||||||
extraGroups = mkIf (cfg.projectGroup != null) [cfg.projectGroup];
|
|
||||||
description = "Isolated Pi agent user";
|
|
||||||
home = cfg.stateDir;
|
|
||||||
createHome = true;
|
|
||||||
shell = pkgs.bashInteractive;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d ${cfg.stateDir} 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/.pi 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/.pi/agent 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/.pi/agent/sessions 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/.project-mounts 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/projects 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/.npm 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/.npm-global 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/.npm-global/bin 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
"d ${cfg.stateDir}/.npm-global/lib 0750 ${cfg.user} ${cfg.group} - -"
|
|
||||||
];
|
|
||||||
|
|
||||||
# Wrapper is canonical when enabled; raw package on PATH is optional and
|
|
||||||
# disabled by default to reduce bypass opportunities.
|
|
||||||
environment.systemPackages =
|
|
||||||
optional cfg.wrapper.enable wrapper
|
|
||||||
++ optional ((!cfg.wrapper.enable) || (!cfg.wrapper.hideDirectBinary)) cfg.package;
|
|
||||||
|
|
||||||
security.sudo.extraRules = mkIf (cfg.wrapper.enable && hostUserNames != []) [
|
|
||||||
{
|
|
||||||
users = hostUserNames;
|
|
||||||
commands = [
|
|
||||||
{
|
|
||||||
command = "${runner}/bin/${cfg.wrapper.runnerName}";
|
|
||||||
options = ["NOPASSWD"];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
# 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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
{inputs, ...}: {
|
|
||||||
# This one brings our custom packages from the 'pkgs' directory
|
|
||||||
additions = final: prev:
|
|
||||||
(import ../pkgs {pkgs = final;})
|
|
||||||
# // (inputs.hyprpanel.overlay final prev)
|
|
||||||
// {rose-pine-hyprcursor = inputs.rose-pine-hyprcursor.packages.${prev.stdenv.hostPlatform.system}.default;};
|
|
||||||
|
|
||||||
# This one contains whatever you want to overlay
|
|
||||||
# You can change versions, add patches, set compilation flags, anything really.
|
|
||||||
# https://nixos.wiki/wiki/Overlays
|
|
||||||
modifications = final: prev:
|
|
||||||
# Import all package modifications from mods directory
|
|
||||||
(import ./mods/default.nix {inherit prev;})
|
|
||||||
// {
|
|
||||||
# Direct configuration overrides
|
|
||||||
brave = prev.brave.override {
|
|
||||||
commandLineArgs = "--password-store=gnome-libsecret";
|
|
||||||
};
|
|
||||||
|
|
||||||
# nodejs_24 = inputs.nixpkgs-stable.legacyPackages.${prev.system}.nodejs_24;
|
|
||||||
# paperless-ngx = inputs.nixpkgs-45570c2.legacyPackages.${prev.system}.paperless-ngx;
|
|
||||||
# anytype-heart = inputs.nixpkgs-9e58ed7.legacyPackages.${prev.system}.anytype-heart;
|
|
||||||
# trezord = inputs.nixpkgs-2744d98.legacyPackages.${prev.system}.trezord;
|
|
||||||
# mesa = inputs.nixpkgs-master.legacyPackages.${prev.system}.mesa;
|
|
||||||
# hyprpanel = inputs.hyprpanel.packages.${prev.system}.default.overrideAttrs (prev: {
|
|
||||||
# version = "latest"; # or whatever version you want
|
|
||||||
# src = final.fetchFromGitHub {
|
|
||||||
# owner = "Jas-SinghFSU";
|
|
||||||
# repo = "HyprPanel";
|
|
||||||
# rev = "master"; # or a specific commit hash
|
|
||||||
# hash = "sha256-l623fIVhVCU/ylbBmohAtQNbK0YrWlEny0sC/vBJ+dU=";
|
|
||||||
# };
|
|
||||||
# });
|
|
||||||
};
|
|
||||||
|
|
||||||
temp-packages = final: _prev: {
|
|
||||||
temp = import inputs.nixpkgs-9e9486b {
|
|
||||||
system = final.stdenv.hostPlatform.system;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
stable-packages = final: _prev: {
|
|
||||||
stable = import inputs.nixpkgs-stable {
|
|
||||||
system = final.stdenv.hostPlatform.system;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pinned-packages = final: _prev: {
|
|
||||||
pinned = import inputs.nixpkgs-9472de4 {
|
|
||||||
system = final.stdenv.hostPlatform.system;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
locked-packages = final: _prev: {
|
|
||||||
locked = import inputs.nixpkgs-locked {
|
|
||||||
system = final.stdenv.hostPlatform.system;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
master-packages = final: _prev: {
|
|
||||||
master = import inputs.nixpkgs-master {
|
|
||||||
system = final.stdenv.hostPlatform.system;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{prev}:
|
|
||||||
prev.beads.overrideAttrs (oldAttrs: rec {
|
|
||||||
version = "0.47.1";
|
|
||||||
|
|
||||||
src = prev.fetchFromGitHub {
|
|
||||||
owner = "steveyegge";
|
|
||||||
repo = "beads";
|
|
||||||
tag = "v${version}";
|
|
||||||
hash = "sha256-DwIR/r1TJnpVd/CT1E2OTkAjU7k9/KHbcVwg5zziFVg=";
|
|
||||||
};
|
|
||||||
|
|
||||||
vendorHash = "sha256-pY5m5ODRgqghyELRwwxOr+xlW41gtJWLXaW53GlLaFw=";
|
|
||||||
|
|
||||||
# Tests require git worktree operations that fail in Nix sandbox
|
|
||||||
doCheck = false;
|
|
||||||
})
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{prev}: {
|
|
||||||
# Package modifications
|
|
||||||
# This overlay contains package overrides and modifications
|
|
||||||
|
|
||||||
# n8n = import ./n8n.nix {inherit prev;};
|
|
||||||
# beads = import ./beads.nix {inherit prev;};
|
|
||||||
|
|
||||||
# Add more modifications here as needed
|
|
||||||
# example-package = prev.example-package.override { ... };
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{prev}:
|
|
||||||
prev.n8n.overrideAttrs (oldAttrs: rec {
|
|
||||||
version = "2.4.1";
|
|
||||||
|
|
||||||
src = prev.fetchFromGitHub {
|
|
||||||
owner = "n8n-io";
|
|
||||||
repo = "n8n";
|
|
||||||
rev = "n8n@${version}";
|
|
||||||
hash = "sha256-EQP9ZI8kt30SUYE1+/UUpxQXpavzKqDu8qE24zsNifg=";
|
|
||||||
};
|
|
||||||
|
|
||||||
pnpmDeps = prev.pnpm_10.fetchDeps {
|
|
||||||
pname = oldAttrs.pname;
|
|
||||||
inherit version src;
|
|
||||||
fetcherVersion = 1;
|
|
||||||
hash = "sha256-Q30IuFEQD3896Hg0HCLd38YE2i8fJn74JY0o95LKJis=";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# 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)
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
lib,
|
|
||||||
fetchFromGitHub,
|
|
||||||
nix-update-script,
|
|
||||||
rustPlatform,
|
|
||||||
pkg-config,
|
|
||||||
perl,
|
|
||||||
openssl,
|
|
||||||
}:
|
|
||||||
rustPlatform.buildRustPackage rec {
|
|
||||||
pname = "code2prompt";
|
|
||||||
version = "4.2.0";
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "mufeedvh";
|
|
||||||
repo = "code2prompt";
|
|
||||||
rev = "v${version}";
|
|
||||||
hash = "sha256-Gh8SsSTZW7QlyyC3SWJ5pOK2x85/GT7+LPJn2Jeczpc=";
|
|
||||||
};
|
|
||||||
|
|
||||||
cargoLock = {
|
|
||||||
lockFile = src + "/Cargo.lock";
|
|
||||||
};
|
|
||||||
|
|
||||||
buildAndTestSubdir = "crates/code2prompt";
|
|
||||||
|
|
||||||
nativeBuildInputs = [pkg-config perl];
|
|
||||||
|
|
||||||
buildInputs = [openssl];
|
|
||||||
|
|
||||||
passthru.updateScript = nix-update-script {};
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "A CLI tool that converts your codebase into a single LLM prompt with a source tree, prompt templating, and token counting";
|
|
||||||
homepage = "https://github.com/mufeedvh/code2prompt";
|
|
||||||
license = licenses.mit;
|
|
||||||
platforms = platforms.linux;
|
|
||||||
mainProgram = "code2prompt";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
pkgs,
|
|
||||||
inputs,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
system = pkgs.stdenv.hostPlatform.system;
|
|
||||||
in {
|
|
||||||
# Custom packages registry
|
|
||||||
# Each package is defined in its own directory under pkgs/
|
|
||||||
sidecar = pkgs.callPackage ./sidecar {};
|
|
||||||
td = pkgs.callPackage ./td {};
|
|
||||||
code2prompt = pkgs.callPackage ./code2prompt {};
|
|
||||||
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 {};
|
|
||||||
n8n = pkgs.callPackage ./n8n {};
|
|
||||||
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 {};
|
|
||||||
zellij-ps = pkgs.callPackage ./zellij-ps {};
|
|
||||||
vibetyper = pkgs.callPackage ./vibetyper {};
|
|
||||||
|
|
||||||
# Imported from flake inputs (pass-through, no modifications)
|
|
||||||
basecamp = inputs.basecamp.packages.${system}.default;
|
|
||||||
openspec = inputs.openspec.packages.${system}.default;
|
|
||||||
|
|
||||||
# Imported from flake inputs (with local modifications)
|
|
||||||
opencode-desktop = pkgs.callPackage ./opencode-desktop {inherit inputs;};
|
|
||||||
# opencode-desktop = inputs.opencode.packages.${pkgs.system}.desktop;
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
{
|
|
||||||
appimageTools,
|
|
||||||
fetchurl,
|
|
||||||
lib,
|
|
||||||
nodejs,
|
|
||||||
uv,
|
|
||||||
python3,
|
|
||||||
nix-update-script,
|
|
||||||
}: let
|
|
||||||
pname = "eigent";
|
|
||||||
version = "0.0.90";
|
|
||||||
src = fetchurl {
|
|
||||||
url = "https://github.com/eigent-ai/eigent/releases/download/v${version}/Eigent-${version}.AppImage";
|
|
||||||
hash = "sha256-mwCBx+D6mgGqQa8bDuUpo3h49EwFVkwasJwaYc6aXFE=";
|
|
||||||
};
|
|
||||||
appimageContents = appimageTools.extractType2 {inherit pname version src;};
|
|
||||||
in
|
|
||||||
appimageTools.wrapType2 {
|
|
||||||
inherit pname version src;
|
|
||||||
|
|
||||||
extraPkgs = _: [
|
|
||||||
nodejs
|
|
||||||
uv
|
|
||||||
python3
|
|
||||||
];
|
|
||||||
|
|
||||||
# Runs before bubblewrap launches — sets up writable state for the sandbox.
|
|
||||||
extraPreBwrapCmds = ''
|
|
||||||
# eigent writes to multiple dirs under resources/ at runtime:
|
|
||||||
# prebuilt/ → pyvenv.cfg, .terminal_venv_fixed sentinel
|
|
||||||
# backend/ → creates runtime/ dir for temporary state
|
|
||||||
# Nix store is read-only → EROFS. Copy to writable location on first
|
|
||||||
# launch (or when the package version changes).
|
|
||||||
DATA_DIR="$HOME/.local/share/${pname}"
|
|
||||||
mkdir -p "$DATA_DIR"
|
|
||||||
for subdir in prebuilt backend; do
|
|
||||||
SRC="${appimageContents}/resources/$subdir"
|
|
||||||
DST="$DATA_DIR/$subdir"
|
|
||||||
if [ ! -f "$DST/.nix-src" ] || [ "$(cat "$DST/.nix-src")" != "${appimageContents}" ]; then
|
|
||||||
rm -rf "$DST"
|
|
||||||
cp -r "$SRC" "$DST"
|
|
||||||
chmod -R u+w "$DST"
|
|
||||||
echo "${appimageContents}" > "$DST/.nix-src"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
'';
|
|
||||||
|
|
||||||
# Bind-mount writable copies over the read-only store paths so the app
|
|
||||||
# sees its files at the expected locations but can write to them.
|
|
||||||
extraBwrapArgs = [
|
|
||||||
"--bind $HOME/.local/share/${pname}/prebuilt ${appimageContents}/resources/prebuilt"
|
|
||||||
"--bind $HOME/.local/share/${pname}/backend ${appimageContents}/resources/backend"
|
|
||||||
];
|
|
||||||
|
|
||||||
extraInstallCommands = ''
|
|
||||||
install -m 444 -D ${appimageContents}/eigent.desktop -t $out/share/applications
|
|
||||||
substituteInPlace $out/share/applications/eigent.desktop \
|
|
||||||
--replace-fail 'Exec=AppRun --no-sandbox %U' 'Exec=${pname} %U'
|
|
||||||
install -m 444 -D ${appimageContents}/eigent.png \
|
|
||||||
$out/share/icons/hicolor/256x256/apps/eigent.png
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru = {
|
|
||||||
updateScript = nix-update-script {};
|
|
||||||
};
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "Open source AI cowork desktop app — local alternative to Claude Cowork";
|
|
||||||
homepage = "https://github.com/eigent-ai/eigent";
|
|
||||||
license = lib.licenses.asl20;
|
|
||||||
platforms = lib.platforms.linux;
|
|
||||||
mainProgram = "eigent";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
{
|
|
||||||
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";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
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";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "1.2.2",
|
|
||||||
"sources": {
|
|
||||||
"aarch64-linux": {
|
|
||||||
"url": "https://github.com/kestra-io/kestractl/releases/download/1.2.2/kestractl_1.2.2_linux_arm64.tar.gz",
|
|
||||||
"hash": "sha256-sidFsCZPnJ07PM5QayPBqaqlBBJTLEdecfd0AWnL7Yo="
|
|
||||||
},
|
|
||||||
"x86_64-linux": {
|
|
||||||
"url": "https://github.com/kestra-io/kestractl/releases/download/1.2.2/kestractl_1.2.2_linux_amd64.tar.gz",
|
|
||||||
"hash": "sha256-0C2naN2ougBJSY2z2m6eORnLkLen87HD+a+gvtrUvdw="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
{
|
|
||||||
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";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
{
|
|
||||||
lib,
|
|
||||||
nix-update-script,
|
|
||||||
python3,
|
|
||||||
fetchFromGitHub,
|
|
||||||
}:
|
|
||||||
python3.pkgs.buildPythonPackage rec {
|
|
||||||
pname = "mem0ai";
|
|
||||||
version = "1.0.9";
|
|
||||||
pyproject = true;
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "mem0ai";
|
|
||||||
repo = "mem0";
|
|
||||||
rev = "v${version}";
|
|
||||||
hash = "sha256-tcWH5VbjIBSHinfjirxbUhxqgU0xOUlcHTQHraMuALg=";
|
|
||||||
};
|
|
||||||
|
|
||||||
# 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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
#!/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)
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
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, privacy‑preserving AI workflows entirely on your local machine.";
|
|
||||||
license = lib.licenses.unfree;
|
|
||||||
platforms = lib.platforms.linux;
|
|
||||||
mainProgram = "msty-studio";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
{
|
|
||||||
stdenv,
|
|
||||||
lib,
|
|
||||||
nixosTests,
|
|
||||||
fetchFromGitHub,
|
|
||||||
nodejs,
|
|
||||||
pnpm_10,
|
|
||||||
fetchPnpmDeps,
|
|
||||||
pnpmConfigHook,
|
|
||||||
python3,
|
|
||||||
node-gyp,
|
|
||||||
cctools,
|
|
||||||
xcbuild,
|
|
||||||
libkrb5,
|
|
||||||
libmongocrypt,
|
|
||||||
libpq,
|
|
||||||
makeWrapper,
|
|
||||||
}: let
|
|
||||||
python = python3.withPackages (
|
|
||||||
ps:
|
|
||||||
with ps; [
|
|
||||||
websockets
|
|
||||||
]
|
|
||||||
);
|
|
||||||
in
|
|
||||||
stdenv.mkDerivation (finalAttrs: {
|
|
||||||
pname = "n8n";
|
|
||||||
version = "2.14.2";
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "n8n-io";
|
|
||||||
repo = "n8n";
|
|
||||||
tag = "n8n@${finalAttrs.version}";
|
|
||||||
hash = "sha256-nWV3DFDkBlfDdoOxwYB0HSrTyKpTt70YxAQYUPartkE=";
|
|
||||||
};
|
|
||||||
|
|
||||||
pnpmDeps = fetchPnpmDeps {
|
|
||||||
inherit (finalAttrs) pname version src;
|
|
||||||
pnpm = pnpm_10;
|
|
||||||
fetcherVersion = 3;
|
|
||||||
hash = "sha256-0SnPF3CgIja3M1ubLrwyFcx7vY0eHz9DEgn/gDLXN80=";
|
|
||||||
};
|
|
||||||
|
|
||||||
nativeBuildInputs =
|
|
||||||
[
|
|
||||||
pnpmConfigHook
|
|
||||||
pnpm_10
|
|
||||||
python3 # required to build sqlite3 bindings
|
|
||||||
node-gyp # required to build sqlite3 bindings
|
|
||||||
makeWrapper
|
|
||||||
]
|
|
||||||
++ lib.optional stdenv.hostPlatform.isDarwin [
|
|
||||||
cctools
|
|
||||||
xcbuild
|
|
||||||
];
|
|
||||||
|
|
||||||
buildInputs = [
|
|
||||||
nodejs
|
|
||||||
libkrb5
|
|
||||||
libmongocrypt
|
|
||||||
libpq
|
|
||||||
];
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
runHook preBuild
|
|
||||||
|
|
||||||
pushd node_modules/sqlite3
|
|
||||||
node-gyp rebuild
|
|
||||||
popd
|
|
||||||
|
|
||||||
# isolated-vm is a native addon required by n8n-nodes-base (Merge node SQL sandbox)
|
|
||||||
# since n8n 2.11.x; must be compiled before pnpm build runs generate-metadata
|
|
||||||
pushd node_modules/isolated-vm
|
|
||||||
node-gyp rebuild
|
|
||||||
popd
|
|
||||||
|
|
||||||
# TODO: use deploy after resolved https://github.com/pnpm/pnpm/issues/5315
|
|
||||||
pnpm build --filter=n8n
|
|
||||||
|
|
||||||
runHook postBuild
|
|
||||||
'';
|
|
||||||
|
|
||||||
preInstall = ''
|
|
||||||
echo "Removing non-deterministic and unnecessary files"
|
|
||||||
|
|
||||||
find -type d -name .turbo -exec rm -rf {} +
|
|
||||||
rm node_modules/.modules.yaml
|
|
||||||
rm packages/nodes-base/dist/types/nodes.json
|
|
||||||
|
|
||||||
CI=true pnpm --ignore-scripts prune --prod
|
|
||||||
find -type f \( -name "*.ts" -o -name "*.map" \) -exec rm -rf {} +
|
|
||||||
rm -rf node_modules/.pnpm/{typescript*,prettier*}
|
|
||||||
shopt -s globstar
|
|
||||||
# https://github.com/pnpm/pnpm/issues/3645
|
|
||||||
find node_modules packages/**/node_modules -xtype l -delete
|
|
||||||
|
|
||||||
echo "Removed non-deterministic and unnecessary files"
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
|
|
||||||
mkdir -p $out/{bin,lib/n8n}
|
|
||||||
cp -r {packages,node_modules} $out/lib/n8n
|
|
||||||
|
|
||||||
makeWrapper $out/lib/n8n/packages/cli/bin/n8n $out/bin/n8n \
|
|
||||||
--set N8N_RELEASE_TYPE "stable"
|
|
||||||
|
|
||||||
# JavaScript runner
|
|
||||||
makeWrapper ${nodejs}/bin/node $out/bin/n8n-task-runner \
|
|
||||||
--add-flags "$out/lib/n8n/packages/@n8n/task-runner/dist/start.js"
|
|
||||||
|
|
||||||
# Python runner
|
|
||||||
mkdir -p $out/lib/n8n-task-runner-python
|
|
||||||
cp -r packages/@n8n/task-runner-python/* $out/lib/n8n-task-runner-python/
|
|
||||||
makeWrapper ${python}/bin/python $out/bin/n8n-task-runner-python \
|
|
||||||
--add-flags "$out/lib/n8n-task-runner-python/src/main.py" \
|
|
||||||
--prefix PYTHONPATH : "$out/lib/n8n-task-runner-python"
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru = {
|
|
||||||
tests = nixosTests.n8n;
|
|
||||||
updateScript = ./update.sh;
|
|
||||||
};
|
|
||||||
|
|
||||||
# this package has ~80000 files, these take too long and seem to be unnecessary
|
|
||||||
dontStrip = true;
|
|
||||||
dontPatchELF = true;
|
|
||||||
dontRewriteSymlinks = true;
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "Free and source-available fair-code licensed workflow automation tool";
|
|
||||||
longDescription = ''
|
|
||||||
Free and source-available fair-code licensed workflow automation tool.
|
|
||||||
Easily automate tasks across different services.
|
|
||||||
'';
|
|
||||||
homepage = "https://n8n.io";
|
|
||||||
changelog = "https://github.com/n8n-io/n8n/releases/tag/n8n@${finalAttrs.version}";
|
|
||||||
maintainers = with lib.maintainers; [
|
|
||||||
gepbird
|
|
||||||
AdrienLemaire
|
|
||||||
sweenu
|
|
||||||
wrbbz
|
|
||||||
];
|
|
||||||
license = lib.licenses.sustainableUse;
|
|
||||||
mainProgram = "n8n";
|
|
||||||
platforms = lib.platforms.unix;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user