docs: add hierarchical AGENTS.md knowledge base
- Update root AGENTS.md with regenerative content (144 lines, telegraphic) - Add pkgs/AGENTS.md for package registry conventions (33 lines) - Add docs/AGENTS.md for documentation structure (34 lines) - All files follow telegraphic style, no redundancy with parent - Preserves existing modules/home-manager/AGENTS.md Hierarchy: ./AGENTS.md (root) ├── pkgs/AGENTS.md ├── docs/AGENTS.md └── modules/home-manager/AGENTS.md (existing)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -31,6 +31,3 @@ test-result/
|
|||||||
# Local configuration (if you want to keep local overrides)
|
# Local configuration (if you want to keep local overrides)
|
||||||
local.nix
|
local.nix
|
||||||
flake.lock.bak
|
flake.lock.bak
|
||||||
|
|
||||||
# Documentation
|
|
||||||
docs/
|
|
||||||
|
|||||||
141
AGENTS.md
141
AGENTS.md
@@ -1,14 +1,14 @@
|
|||||||
# m3ta-nixpkgs Knowledge Base
|
# m3ta-nixpkgs Knowledge Base
|
||||||
|
|
||||||
**Generated:** 2025-12-29
|
**Generated:** 2025-12-30
|
||||||
**Commit:** 9092e6d
|
**Commit:** c5e1610
|
||||||
**Branch:** master
|
**Branch:** master
|
||||||
|
|
||||||
## Overview
|
## OVERVIEW
|
||||||
|
|
||||||
Personal Nix flake: custom packages, overlays, NixOS/Home Manager modules, dev shells. Flakes-only (no channels).
|
Personal Nix flake: custom packages, overlays, NixOS/Home Manager modules, dev shells. Flakes-only (no channels).
|
||||||
|
|
||||||
## Structure
|
## STRUCTURE
|
||||||
|
|
||||||
```
|
```
|
||||||
.
|
.
|
||||||
@@ -24,7 +24,7 @@ Personal Nix flake: custom packages, overlays, NixOS/Home Manager modules, dev s
|
|||||||
└── examples/ # Usage examples
|
└── examples/ # Usage examples
|
||||||
```
|
```
|
||||||
|
|
||||||
## Where to Look
|
## WHERE TO LOOK
|
||||||
|
|
||||||
| Task | Location | Notes |
|
| Task | Location | Notes |
|
||||||
|------|----------|-------|
|
|------|----------|-------|
|
||||||
@@ -35,23 +35,7 @@ Personal Nix flake: custom packages, overlays, NixOS/Home Manager modules, dev s
|
|||||||
| Add dev shell | `shells/<name>.nix` | Register in `shells/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` |
|
| Use port management | `config.m3ta.ports.get "service"` | Host-specific via `hostOverrides` |
|
||||||
|
|
||||||
## Commands
|
## CONVENTIONS
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check # Validate flake
|
|
||||||
nix fmt # Format (nixpkgs-fmt)
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
**Formatter**: `nix fmt` before commit (nixpkgs-fmt)
|
**Formatter**: `nix fmt` before commit (nixpkgs-fmt)
|
||||||
|
|
||||||
@@ -93,80 +77,47 @@ meta = with lib; {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## Package Patterns
|
## PACKAGE PATTERNS
|
||||||
|
|
||||||
**Rust** (code2prompt):
|
**Rust**: `rustPlatform.buildRustPackage rec { cargoLock.lockFile = src + "/Cargo.lock"; }`
|
||||||
```nix
|
|
||||||
rustPlatform.buildRustPackage rec {
|
**Shell**: `writeShellScriptBin "name" ''script''` or `mkDerivation` with custom `installPhase`
|
||||||
cargoLock.lockFile = src + "/Cargo.lock";
|
|
||||||
}
|
**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 { ... };`
|
||||||
|
|
||||||
|
## 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 (nixpkgs-fmt)
|
||||||
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
**Shell scripts** (launch-webapp):
|
## ANTI-PATTERNS
|
||||||
```nix
|
|
||||||
writeShellScriptBin "name" ''script''
|
|
||||||
# Or mkDerivation with custom installPhase
|
|
||||||
```
|
|
||||||
|
|
||||||
**AppImage** (msty-studio):
|
|
||||||
```nix
|
|
||||||
appimageTools.wrapType2 { ... }
|
|
||||||
```
|
|
||||||
|
|
||||||
**Custom fetcher** (zellij-ps):
|
|
||||||
```nix
|
|
||||||
fetchFromGitea {
|
|
||||||
domain = "code.m3ta.dev";
|
|
||||||
owner = "m3tam3re";
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Module Patterns
|
|
||||||
|
|
||||||
**Simple enable** (zellij-ps.nix):
|
|
||||||
```nix
|
|
||||||
options.cli.zellij-ps = {
|
|
||||||
enable = mkEnableOption "...";
|
|
||||||
someOption = mkOption { type = types.str; default = "..."; };
|
|
||||||
};
|
|
||||||
config = mkIf cfg.enable { home.packages = [...]; };
|
|
||||||
```
|
|
||||||
|
|
||||||
**Multiple conditionals** (editors.nix):
|
|
||||||
```nix
|
|
||||||
config = mkMerge [
|
|
||||||
(mkIf cfg.neovim.enable { ... })
|
|
||||||
(mkIf cfg.zed.enable { ... })
|
|
||||||
(mkIf (cfg.neovim.enable || cfg.zed.enable) { ... })
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
**Shared library** (ports modules):
|
|
||||||
```nix
|
|
||||||
portsLib = import ../../lib/ports.nix { inherit lib; };
|
|
||||||
portHelpers = portsLib.mkPortHelpers { ports = cfg.definitions; ... };
|
|
||||||
```
|
|
||||||
|
|
||||||
## Port Management
|
|
||||||
|
|
||||||
Central port management with host-specific overrides:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
m3ta.ports = {
|
|
||||||
enable = true;
|
|
||||||
definitions = { nginx = 80; grafana = 3000; };
|
|
||||||
hostOverrides.laptop = { nginx = 8080; };
|
|
||||||
currentHost = config.networking.hostName; # NixOS auto
|
|
||||||
};
|
|
||||||
|
|
||||||
# Usage
|
|
||||||
services.nginx.port = config.m3ta.ports.get "nginx";
|
|
||||||
```
|
|
||||||
|
|
||||||
**Generated files**: `/etc/m3ta/ports.json` (NixOS), `~/.config/m3ta/ports.json` (HM)
|
|
||||||
|
|
||||||
## Anti-Patterns
|
|
||||||
|
|
||||||
| Don't | Do Instead |
|
| Don't | Do Instead |
|
||||||
|-------|------------|
|
|-------|------------|
|
||||||
@@ -176,7 +127,7 @@ services.nginx.port = config.m3ta.ports.get "nginx";
|
|||||||
| Skip meta fields | Include all: description, homepage, license, platforms, mainProgram |
|
| Skip meta fields | Include all: description, homepage, license, platforms, mainProgram |
|
||||||
| `with pkgs;` in modules | Explicit `pkgs.package` or `with pkgs; [ ... ]` in lists only |
|
| `with pkgs;` in modules | Explicit `pkgs.package` or `with pkgs; [ ... ]` in lists only |
|
||||||
|
|
||||||
## Commit Format
|
## COMMIT FORMAT
|
||||||
|
|
||||||
```
|
```
|
||||||
type: brief description
|
type: brief description
|
||||||
@@ -184,7 +135,7 @@ type: brief description
|
|||||||
|
|
||||||
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `chore`
|
Types: `feat`, `fix`, `docs`, `style`, `refactor`, `chore`
|
||||||
|
|
||||||
## Gotchas
|
## NOTES
|
||||||
|
|
||||||
- **Hash fetching**: Use `lib.fakeHash` initially, build to get real hash
|
- **Hash fetching**: Use `lib.fakeHash` initially, build to get real hash
|
||||||
- **HM modules**: Category subdirs (`cli/`, `coding/`) have own `default.nix` aggregators
|
- **HM modules**: Category subdirs (`cli/`, `coding/`) have own `default.nix` aggregators
|
||||||
|
|||||||
450
CONTRIBUTING.md
450
CONTRIBUTING.md
@@ -1,450 +0,0 @@
|
|||||||
# Contributing to m3ta-nixpkgs
|
|
||||||
|
|
||||||
Thank you for your interest in contributing to m3ta-nixpkgs! This guide will help you get started with adding packages, modules, and improvements to this repository.
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
- [Getting Started](#getting-started)
|
|
||||||
- [Adding a New Package](#adding-a-new-package)
|
|
||||||
- [Adding a NixOS Module](#adding-a-nixos-module)
|
|
||||||
- [Adding a Home Manager Module](#adding-a-home-manager-module)
|
|
||||||
- [Code Style Guidelines](#code-style-guidelines)
|
|
||||||
- [Testing Your Changes](#testing-your-changes)
|
|
||||||
- [Submitting Changes](#submitting-changes)
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- Nix with flakes enabled
|
|
||||||
- Git
|
|
||||||
- Basic understanding of Nix expressions
|
|
||||||
|
|
||||||
### Enable Flakes
|
|
||||||
|
|
||||||
Add to `~/.config/nix/nix.conf` or `/etc/nix/nix.conf`:
|
|
||||||
|
|
||||||
```
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
```
|
|
||||||
|
|
||||||
### Clone and Setup
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://code.m3ta.dev/m3tam3re/nixpkgs
|
|
||||||
cd m3ta-nixpkgs
|
|
||||||
nix develop # Enter development environment
|
|
||||||
```
|
|
||||||
|
|
||||||
## Adding a New Package
|
|
||||||
|
|
||||||
### Step 1: Create Package Directory
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir pkgs/my-package
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Write the Package Expression
|
|
||||||
|
|
||||||
Create `pkgs/my-package/default.nix` using the template:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp templates/package/default.nix pkgs/my-package/default.nix
|
|
||||||
```
|
|
||||||
|
|
||||||
Edit the file to match your package:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
lib,
|
|
||||||
stdenv,
|
|
||||||
fetchFromGitHub,
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation rec {
|
|
||||||
pname = "my-package";
|
|
||||||
version = "1.0.0";
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "owner";
|
|
||||||
repo = "repo";
|
|
||||||
rev = "v${version}";
|
|
||||||
hash = lib.fakeHash; # Use this initially
|
|
||||||
};
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "A short description";
|
|
||||||
homepage = "https://github.com/owner/repo";
|
|
||||||
license = licenses.mit;
|
|
||||||
platforms = platforms.linux;
|
|
||||||
mainProgram = "my-package";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Get the Correct Hash
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix build .#my-package
|
|
||||||
# The error message will show the correct hash
|
|
||||||
# Replace lib.fakeHash with the actual hash
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Register the Package
|
|
||||||
|
|
||||||
Add to `pkgs/default.nix`:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{pkgs, ...}: {
|
|
||||||
# ... existing packages ...
|
|
||||||
my-package = pkgs.callPackage ./my-package {};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Test the Package
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build the package
|
|
||||||
nix build .#my-package
|
|
||||||
|
|
||||||
# Run the package
|
|
||||||
nix run .#my-package
|
|
||||||
|
|
||||||
# Check if it works
|
|
||||||
./result/bin/my-package --version
|
|
||||||
```
|
|
||||||
|
|
||||||
## Adding a NixOS Module
|
|
||||||
|
|
||||||
### Step 1: Create Module File
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp templates/nixos-module/default.nix modules/nixos/my-module.nix
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Implement the Module
|
|
||||||
|
|
||||||
Edit `modules/nixos/my-module.nix`:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.m3ta.myModule;
|
|
||||||
in {
|
|
||||||
options.m3ta.myModule = {
|
|
||||||
enable = mkEnableOption "my custom module";
|
|
||||||
# Add your options here
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
# Add your configuration here
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Register the Module
|
|
||||||
|
|
||||||
Add to `modules/nixos/default.nix`:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}: {
|
|
||||||
imports = [
|
|
||||||
./my-module.nix # Add this line
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Test the Module
|
|
||||||
|
|
||||||
Create a test configuration or add to your existing NixOS configuration:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
inputs.m3ta-nixpkgs.url = "path:/path/to/m3ta-nixpkgs";
|
|
||||||
|
|
||||||
outputs = {nixpkgs, m3ta-nixpkgs, ...}: {
|
|
||||||
nixosConfigurations.test = nixpkgs.lib.nixosSystem {
|
|
||||||
modules = [
|
|
||||||
m3ta-nixpkgs.nixosModules.default
|
|
||||||
{
|
|
||||||
m3ta.myModule.enable = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Adding a Home Manager Module
|
|
||||||
|
|
||||||
### Step 1: Create Module File
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cp templates/home-manager-module/default.nix modules/home-manager/my-module.nix
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Implement the Module
|
|
||||||
|
|
||||||
Edit `modules/home-manager/my-module.nix`:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
with lib; let
|
|
||||||
cfg = config.programs.myProgram;
|
|
||||||
in {
|
|
||||||
options.programs.myProgram = {
|
|
||||||
enable = mkEnableOption "my program";
|
|
||||||
# Add your options here
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
# Add your configuration here
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Register the Module
|
|
||||||
|
|
||||||
Add to `modules/home-manager/default.nix`:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
# ... existing modules ...
|
|
||||||
myModule = import ./my-module.nix;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Test the Module
|
|
||||||
|
|
||||||
Test with Home Manager:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
inputs.m3ta-nixpkgs.url = "path:/path/to/m3ta-nixpkgs";
|
|
||||||
|
|
||||||
outputs = {home-manager, m3ta-nixpkgs, ...}: {
|
|
||||||
homeConfigurations.test = home-manager.lib.homeManagerConfiguration {
|
|
||||||
modules = [
|
|
||||||
m3ta-nixpkgs.homeManagerModules.default
|
|
||||||
{
|
|
||||||
programs.myProgram.enable = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code Style Guidelines
|
|
||||||
|
|
||||||
### Nix Code Style
|
|
||||||
|
|
||||||
1. **Formatting**: Use `nixpkgs-fmt` for consistent formatting
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix fmt
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Naming Conventions**:
|
|
||||||
- Package names: lowercase with hyphens (`my-package`)
|
|
||||||
- Module options: camelCase (`myModule`)
|
|
||||||
- Variables: camelCase (`cfg`, `myVar`)
|
|
||||||
|
|
||||||
3. **File Structure**:
|
|
||||||
- One package per directory
|
|
||||||
- Use `default.nix` for the main expression
|
|
||||||
- Keep related files together
|
|
||||||
|
|
||||||
4. **Comments**:
|
|
||||||
- Add comments for non-obvious code
|
|
||||||
- Document complex expressions
|
|
||||||
- Explain why, not what
|
|
||||||
|
|
||||||
### Example Good Practice
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
lib,
|
|
||||||
stdenv,
|
|
||||||
fetchFromGitHub,
|
|
||||||
# Group related dependencies
|
|
||||||
# Build tools
|
|
||||||
cmake,
|
|
||||||
pkg-config,
|
|
||||||
# Libraries
|
|
||||||
openssl,
|
|
||||||
zlib,
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation rec {
|
|
||||||
pname = "example";
|
|
||||||
version = "1.0.0";
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "example";
|
|
||||||
repo = pname;
|
|
||||||
rev = "v${version}";
|
|
||||||
hash = "sha256-...";
|
|
||||||
};
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
|
||||||
cmake
|
|
||||||
pkg-config
|
|
||||||
];
|
|
||||||
|
|
||||||
buildInputs = [
|
|
||||||
openssl
|
|
||||||
zlib
|
|
||||||
];
|
|
||||||
|
|
||||||
# Explain non-obvious configuration
|
|
||||||
cmakeFlags = [
|
|
||||||
"-DENABLE_FEATURE=ON" # Required for proper functionality
|
|
||||||
];
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "Clear, concise description";
|
|
||||||
homepage = "https://example.com";
|
|
||||||
license = licenses.mit;
|
|
||||||
maintainers = with maintainers; [];
|
|
||||||
platforms = platforms.linux;
|
|
||||||
mainProgram = "example";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing Your Changes
|
|
||||||
|
|
||||||
### 1. Check Flake Validity
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake check
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Build All Packages
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix flake show # See all outputs
|
|
||||||
nix build .#package-name
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Test in a Clean Environment
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build without any cached results
|
|
||||||
nix build .#package-name --rebuild
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Test Module Integration
|
|
||||||
|
|
||||||
Test modules in a VM:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nixos-rebuild build-vm --flake .#test-config
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Verify Metadata
|
|
||||||
|
|
||||||
Check that package metadata is complete:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
nix eval .#packages.x86_64-linux.my-package.meta --json | jq
|
|
||||||
```
|
|
||||||
|
|
||||||
## Submitting Changes
|
|
||||||
|
|
||||||
### Before Submitting
|
|
||||||
|
|
||||||
- [ ] Code follows style guidelines
|
|
||||||
- [ ] Package builds successfully
|
|
||||||
- [ ] Tests pass (if applicable)
|
|
||||||
- [ ] Documentation is updated
|
|
||||||
- [ ] Commit messages are clear and descriptive
|
|
||||||
|
|
||||||
- [ ] CI workflows pass (check GitHub Actions)
|
|
||||||
|
|
||||||
### Commit Message Format
|
|
||||||
|
|
||||||
```
|
|
||||||
type: brief description
|
|
||||||
|
|
||||||
Longer explanation if needed.
|
|
||||||
|
|
||||||
- Detail 1
|
|
||||||
- Detail 2
|
|
||||||
```
|
|
||||||
|
|
||||||
Types:
|
|
||||||
|
|
||||||
- `feat`: New feature (package, module)
|
|
||||||
- `fix`: Bug fix
|
|
||||||
- `docs`: Documentation changes
|
|
||||||
- `style`: Code style changes
|
|
||||||
- `refactor`: Code refactoring
|
|
||||||
- `chore`: Maintenance tasks
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
```
|
|
||||||
feat: add hyprpaper-random package
|
|
||||||
|
|
||||||
Add a random wallpaper selector for Hyprpaper.
|
|
||||||
Includes systemd timer integration.
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
fix: correct msty-studio dependencies
|
|
||||||
|
|
||||||
Add missing libGL dependency that caused runtime errors.
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
docs: update README with usage instructions
|
|
||||||
|
|
||||||
Add detailed instructions for using packages and modules.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Best Practices
|
|
||||||
|
|
||||||
### Security
|
|
||||||
|
|
||||||
- Never include API keys, passwords, or secrets
|
|
||||||
- Use `lib.fakeHash` initially, then update with correct hash
|
|
||||||
- Review dependencies for known vulnerabilities
|
|
||||||
|
|
||||||
### Performance
|
|
||||||
|
|
||||||
- Use `callPackage` for better caching
|
|
||||||
- Avoid unnecessary `import` statements
|
|
||||||
- Use overlays efficiently
|
|
||||||
|
|
||||||
### Maintainability
|
|
||||||
|
|
||||||
- Keep packages focused and simple
|
|
||||||
- Document complex logic
|
|
||||||
- Follow nixpkgs conventions
|
|
||||||
- Update regularly
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
- Check [Nix Pills](https://nixos.org/guides/nix-pills/)
|
|
||||||
- Read [Nixpkgs Manual](https://nixos.org/manual/nixpkgs/stable/)
|
|
||||||
- Ask in [NixOS Discourse](https://discourse.nixos.org/)
|
|
||||||
- Join [NixOS Matrix](https://matrix.to/#/#nix:nixos.org)
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
By contributing, you agree that your contributions will be licensed under the same license as the project.
|
|
||||||
@@ -1,230 +0,0 @@
|
|||||||
# Quick Start Guide - Port Management Module
|
|
||||||
|
|
||||||
Get started with centralized port management in 5 minutes!
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### Step 1: Add to your flake inputs
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
||||||
m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Choose your configuration type
|
|
||||||
|
|
||||||
## For NixOS Systems
|
|
||||||
|
|
||||||
### Basic Setup
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
imports = [ inputs.m3ta-nixpkgs.nixosModules.default ];
|
|
||||||
|
|
||||||
m3ta.ports = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
definitions = {
|
|
||||||
nginx = 80;
|
|
||||||
ssh = 22;
|
|
||||||
grafana = 3000;
|
|
||||||
};
|
|
||||||
|
|
||||||
hostOverrides = {
|
|
||||||
laptop = { nginx = 8080; ssh = 2222; };
|
|
||||||
server = {}; # Uses defaults
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using Ports
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# In any NixOS service configuration:
|
|
||||||
services.nginx.defaultHTTPListenPort = config.m3ta.ports.get "nginx";
|
|
||||||
services.openssh.ports = [ (config.m3ta.ports.get "ssh") ];
|
|
||||||
|
|
||||||
# Firewall rules:
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
(config.m3ta.ports.get "ssh")
|
|
||||||
(config.m3ta.ports.get "nginx")
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
## For Home Manager
|
|
||||||
|
|
||||||
### Basic Setup
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
imports = [ inputs.m3ta-nixpkgs.homeManagerModules.default ];
|
|
||||||
|
|
||||||
m3ta.ports = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
definitions = {
|
|
||||||
vite-dev = 5173;
|
|
||||||
jupyter = 8888;
|
|
||||||
local-api = 8000;
|
|
||||||
};
|
|
||||||
|
|
||||||
hostOverrides = {
|
|
||||||
laptop = { vite-dev = 5174; };
|
|
||||||
desktop = { jupyter = 9999; };
|
|
||||||
};
|
|
||||||
|
|
||||||
currentHost = "laptop"; # Set your hostname
|
|
||||||
generateEnvVars = true; # Creates PORT_* environment variables
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using Ports
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# Shell aliases:
|
|
||||||
programs.bash.shellAliases = {
|
|
||||||
dev = "PORT=${toString (config.m3ta.ports.get "vite-dev")} npm run dev";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Environment variables:
|
|
||||||
home.sessionVariables = {
|
|
||||||
DEV_URL = "http://localhost:${toString (config.m3ta.ports.get "vite-dev")}";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Config files:
|
|
||||||
home.file.".config/myapp/config.json".text = builtins.toJSON {
|
|
||||||
port = config.m3ta.ports.get "vite-dev";
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Patterns
|
|
||||||
|
|
||||||
### Multi-Host Configuration
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# shared-ports.nix
|
|
||||||
{
|
|
||||||
ports = {
|
|
||||||
nginx = 80;
|
|
||||||
ssh = 22;
|
|
||||||
grafana = 3000;
|
|
||||||
};
|
|
||||||
|
|
||||||
hostOverrides = {
|
|
||||||
laptop = { nginx = 8080; ssh = 2222; };
|
|
||||||
server = {};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# In your flake.nix
|
|
||||||
let
|
|
||||||
sharedPorts = import ./shared-ports.nix;
|
|
||||||
in {
|
|
||||||
nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
|
|
||||||
modules = [
|
|
||||||
m3ta-nixpkgs.nixosModules.default
|
|
||||||
{
|
|
||||||
m3ta.ports = {
|
|
||||||
enable = true;
|
|
||||||
definitions = sharedPorts.ports;
|
|
||||||
hostOverrides = sharedPorts.hostOverrides;
|
|
||||||
currentHost = "laptop";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Proxy Configuration
|
|
||||||
|
|
||||||
```nix
|
|
||||||
services.nginx.virtualHosts."example.com" = {
|
|
||||||
locations."/grafana/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:${toString (config.m3ta.ports.get "grafana")}";
|
|
||||||
};
|
|
||||||
locations."/prometheus/" = {
|
|
||||||
proxyPass = "http://127.0.0.1:${toString (config.m3ta.ports.get "prometheus")}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Container Services
|
|
||||||
|
|
||||||
```nix
|
|
||||||
virtualisation.oci-containers.containers.grafana = {
|
|
||||||
image = "grafana/grafana:latest";
|
|
||||||
ports = [
|
|
||||||
"${toString (config.m3ta.ports.get "grafana")}:3000"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Available Functions
|
|
||||||
|
|
||||||
| Function | Description | Example |
|
|
||||||
| ----------------------------------------------- | -------------------------- | ----------------------------------------------- |
|
|
||||||
| `config.m3ta.ports.get "service"` | Get port for current host | `config.m3ta.ports.get "nginx"` |
|
|
||||||
| `config.m3ta.ports.getForHost "host" "service"` | Get port for specific host | `config.m3ta.ports.getForHost "laptop" "nginx"` |
|
|
||||||
| `config.m3ta.ports.all` | All ports (merged) | `config.m3ta.ports.all` |
|
|
||||||
| `config.m3ta.ports.services` | List service names | `config.m3ta.ports.services` |
|
|
||||||
|
|
||||||
## Debugging
|
|
||||||
|
|
||||||
### View all configured ports
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# NixOS
|
|
||||||
cat /etc/m3ta/ports.json | jq
|
|
||||||
|
|
||||||
# Home Manager
|
|
||||||
cat ~/.config/m3ta/ports.json | jq
|
|
||||||
```
|
|
||||||
|
|
||||||
### Check what port is being used
|
|
||||||
|
|
||||||
```nix
|
|
||||||
# Add to your config temporarily
|
|
||||||
environment.etc."debug-ports.txt".text = ''
|
|
||||||
nginx: ${toString (config.m3ta.ports.get "nginx")}
|
|
||||||
ssh: ${toString (config.m3ta.ports.get "ssh")}
|
|
||||||
all: ${builtins.toJSON config.m3ta.ports.all}
|
|
||||||
'';
|
|
||||||
```
|
|
||||||
|
|
||||||
## Implementation Details
|
|
||||||
|
|
||||||
The port management module is implemented across several files:
|
|
||||||
|
|
||||||
- `lib/ports.nix`: Core utilities for port management
|
|
||||||
- `modules/nixos/ports.nix`: NixOS module implementation
|
|
||||||
- `modules/home-manager/ports.nix`: Home Manager module implementation
|
|
||||||
|
|
||||||
For detailed implementation and source code, see these files in the repository.
|
|
||||||
|
|
||||||
## Common Issues
|
|
||||||
|
|
||||||
**"Service not defined" error**
|
|
||||||
|
|
||||||
- Make sure the service is in your `definitions` block
|
|
||||||
|
|
||||||
**Wrong port being used**
|
|
||||||
|
|
||||||
- Check your `currentHost` matches your actual hostname
|
|
||||||
- Verify overrides in `/etc/m3ta/ports.json` or `~/.config/m3ta/ports.json`
|
|
||||||
|
|
||||||
**Type errors**
|
|
||||||
|
|
||||||
- Ports must be integers: `nginx = 80;` not `nginx = "80";`
|
|
||||||
|
|
||||||
## Need Help?
|
|
||||||
|
|
||||||
Open an issue at: https://code.m3ta.dev/m3tam3re/nixpkgs
|
|
||||||
491
README.md
491
README.md
@@ -1,62 +1,30 @@
|
|||||||
# m3ta-nixpkgs
|
# m3ta-nixpkgs
|
||||||
|
|
||||||
My personal Nix repository containing custom packages, overlays, NixOS modules, and Home Manager modules.
|
Personal Nix flake repository: custom packages, overlays, NixOS modules, and Home Manager modules.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- 🎁 **Custom Packages**: Collection of personal Nix packages
|
- 🎁 **Custom Packages**: Collection of personal Nix packages
|
||||||
- 🔄 **Overlays**: Package modifications and enhancements
|
- 🔄 **Overlays**: Package modifications and enhancements
|
||||||
- 🐚 **Development Shells**: Pre-configured environments for Python and DevOps
|
- 🐚 **Development Shells**: Pre-configured environments (Python, DevOps)
|
||||||
- ⚙️ **NixOS Modules**: System-level configuration modules
|
- ⚙️ **NixOS Modules**: System-level configuration modules
|
||||||
- 🏠 **Home Manager Modules**: User-level configuration modules
|
- 🏠 **Home Manager Modules**: User-level configuration modules
|
||||||
- 📚 **Library Functions**: Helper utilities for configuration management
|
- 📚 **Library Functions**: Helper utilities for configuration management
|
||||||
- ❄️ **Flakes Only**: Modern Nix flakes support (no channels)
|
- ❄️ **Flakes Only**: Modern Nix flakes support (no channels)
|
||||||
|
|
||||||
## Repository Structure
|
## Quick Links
|
||||||
|
|
||||||
```
|
- 📖 [Full Documentation](./docs)
|
||||||
m3ta-nixpkgs/
|
- 🚀 [Quick Start Guide](./docs/QUICKSTART.md)
|
||||||
├── flake.nix # Main flake configuration
|
- 📚 [Architecture](./docs/ARCHITECTURE.md)
|
||||||
├── pkgs/ # Custom packages
|
- 🤝 [Contributing](./docs/CONTRIBUTING.md)
|
||||||
│ ├── default.nix # Package registry
|
- 📦 [Packages](./docs/packages/)
|
||||||
│ ├── code2prompt/
|
- ⚙️ [Modules](./docs/modules/)
|
||||||
│ ├── hyprpaper-random/
|
- 📖 [Guides](./docs/guides/)
|
||||||
│ ├── launch-webapp/
|
|
||||||
│ ├── msty-studio/
|
|
||||||
│ ├── pomodoro-timer/
|
|
||||||
│ ├── tuxedo-backlight/
|
|
||||||
│ └── zellij-ps/
|
|
||||||
├── shells/ # Development shells
|
|
||||||
│ ├── default.nix # Shell registry (default, python, devops)
|
|
||||||
│ ├── python.nix # Python development environment
|
|
||||||
│ └── devops.nix # DevOps/infrastructure tools
|
|
||||||
├── overlays/ # Overlays
|
|
||||||
│ ├── default.nix
|
|
||||||
│ └── mods/ # Package modifications
|
|
||||||
│ ├── default.nix
|
|
||||||
│ └── n8n.nix
|
|
||||||
├── modules/
|
|
||||||
│ ├── nixos/ # NixOS modules
|
|
||||||
│ │ ├── default.nix
|
|
||||||
│ │ └── ports.nix # Port management module
|
|
||||||
│ └── home-manager/ # Home Manager modules
|
|
||||||
│ ├── default.nix
|
|
||||||
│ ├── ports.nix # Port management module
|
|
||||||
│ └── zellij-ps.nix
|
|
||||||
├── lib/ # Library functions
|
|
||||||
│ ├── default.nix # Library entry point
|
|
||||||
│ └── ports.nix # Port management utilities
|
|
||||||
├── examples/ # Usage examples
|
|
||||||
│ ├── home-manager-standalone.nix
|
|
||||||
│ ├── nixos-configuration.nix
|
|
||||||
└── templates/ # Templates for new packages/modules
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
## Installation
|
||||||
|
|
||||||
### Adding to Your Flake
|
### Add to Your Flake
|
||||||
|
|
||||||
Add this repository to your flake inputs:
|
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{
|
{
|
||||||
@@ -67,446 +35,22 @@ Add this repository to your flake inputs:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using Packages in NixOS Configuration
|
### Quick Start
|
||||||
|
|
||||||
#### Method 1: Using the Overlay
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
nixpkgs.overlays = [
|
|
||||||
inputs.m3ta-nixpkgs.overlays.default
|
|
||||||
];
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
code2prompt
|
|
||||||
hyprpaper-random
|
|
||||||
msty-studio
|
|
||||||
# ... any other custom packages
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Method 2: Direct Package Reference
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
environment.systemPackages = [
|
|
||||||
inputs.m3ta-nixpkgs.packages.${pkgs.stdenv.hostPlatform.system}.code2prompt
|
|
||||||
inputs.m3ta-nixpkgs.packages.${pkgs.stdenv.hostPlatform.system}.hyprpaper-random
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using in Home Manager
|
|
||||||
|
|
||||||
#### With Overlay
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
nixpkgs.overlays = [
|
|
||||||
inputs.m3ta-nixpkgs.overlays.default
|
|
||||||
];
|
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
|
||||||
zellij-ps
|
|
||||||
pomodoro-timer
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### With Home Manager Modules
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
inputs.m3ta-nixpkgs.homeManagerModules.default
|
|
||||||
# Or specific modules:
|
|
||||||
# inputs.m3ta-nixpkgs.homeManagerModules.zellij-ps
|
|
||||||
];
|
|
||||||
|
|
||||||
# Module-specific configuration here
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using NixOS Modules
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
inputs.m3ta-nixpkgs.nixosModules.default
|
|
||||||
# Or specific modules:
|
|
||||||
# inputs.m3ta-nixpkgs.nixosModules.ports
|
|
||||||
];
|
|
||||||
|
|
||||||
# Configure the ports module (if enabled)
|
|
||||||
m3ta.ports = {
|
|
||||||
enable = true;
|
|
||||||
definitions = {
|
|
||||||
nginx = 80;
|
|
||||||
ssh = 22;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building Packages Directly
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build a specific package
|
# Build a package
|
||||||
nix build git+https://code.m3ta.dev/m3tam3re/nixpkgs#code2prompt
|
nix build git+https://code.m3ta.dev/m3tam3re/nixpkgs#code2prompt
|
||||||
|
|
||||||
# Run a package without installing
|
# Run a package
|
||||||
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#zellij-ps
|
nix run git+https://code.m3ta.dev/m3tam3re/nixpkgs#zellij-ps
|
||||||
|
|
||||||
# Install to your profile
|
|
||||||
nix profile install git+https://code.m3ta.dev/m3tam3re/nixpkgs#msty-studio
|
|
||||||
|
|
||||||
# List all available packages
|
# List all available packages
|
||||||
nix flake show git+https://code.m3ta.dev/m3tam3re/nixpkgs
|
nix flake show git+https://code.m3ta.dev/m3tam3re/nixpkgs
|
||||||
```
|
```
|
||||||
|
|
||||||
## Development Shells
|
## Documentation
|
||||||
|
|
||||||
This repository provides pre-configured development environments. All shells are accessible via `nix develop`.
|
For detailed usage, module documentation, package references, and contribution guidelines, see the [full documentation](./docs).
|
||||||
|
|
||||||
### Available Shells
|
|
||||||
|
|
||||||
| Shell | Description | Usage |
|
|
||||||
| --------- | ---------------------------------------------- | ---------------------- |
|
|
||||||
| `default` | Nix development tools for working on this repo | `nix develop` |
|
|
||||||
| `python` | Python with common libraries and tools | `nix develop .#python` |
|
|
||||||
| `devops` | Docker, Kubernetes, Terraform, cloud CLIs | `nix develop .#devops` |
|
|
||||||
|
|
||||||
### Quick Start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Enter a development environment
|
|
||||||
nix develop git+https://code.m3ta.dev/m3tam3re/nixpkgs#python
|
|
||||||
nix develop git+https://code.m3ta.dev/m3tam3re/nixpkgs#devops
|
|
||||||
|
|
||||||
# Run a command in a shell without entering it
|
|
||||||
nix develop git+https://code.m3ta.dev/m3tam3re/nixpkgs#python --command python --version
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using Shells in Home Manager
|
|
||||||
|
|
||||||
Add shells to your home-manager configuration for persistent access:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
inputs.m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
|
|
||||||
|
|
||||||
# Make tools globally available
|
|
||||||
home.packages = with inputs.m3ta-nixpkgs.devShells.${pkgs.stdenv.hostPlatform.system};
|
|
||||||
python.buildInputs ++ devops.buildInputs;
|
|
||||||
|
|
||||||
# Or create aliases
|
|
||||||
programs.zsh.shellAliases = {
|
|
||||||
dev-python = "nix develop ${inputs.m3ta-nixpkgs}#python";
|
|
||||||
dev-devops = "nix develop ${inputs.m3ta-nixpkgs}#devops";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Using Shells in NixOS
|
|
||||||
|
|
||||||
Add shells system-wide:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
inputs.m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
|
|
||||||
|
|
||||||
# Make tools available to all users
|
|
||||||
environment.systemPackages =
|
|
||||||
inputs.m3ta-nixpkgs.devShells.${pkgs.stdenv.hostPlatform.system}.python.buildInputs;
|
|
||||||
|
|
||||||
# System-wide aliases
|
|
||||||
environment.shellAliases = {
|
|
||||||
dev-python = "nix develop ${inputs.m3ta-nixpkgs}#python";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Project-Specific Usage with direnv
|
|
||||||
|
|
||||||
Create `.envrc` in your project directory:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
use flake git+https://code.m3ta.dev/m3tam3re/nixpkgs#python
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run `direnv allow`. The environment activates automatically when you enter the directory!
|
|
||||||
|
|
||||||
### Extending Shells for Your Project
|
|
||||||
|
|
||||||
Create a `flake.nix` in your project that extends a base shell:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
||||||
m3ta-nixpkgs.url = "git+https://code.m3ta.dev/m3tam3re/nixpkgs";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = { nixpkgs, m3ta-nixpkgs, ... }: {
|
|
||||||
devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
|
|
||||||
# Inherit all packages from base Python shell
|
|
||||||
inputsFrom = [ m3ta-nixpkgs.devShells.x86_64-linux.python ];
|
|
||||||
|
|
||||||
# Add project-specific packages
|
|
||||||
buildInputs = [ nixpkgs.legacyPackages.x86_64-linux.postgresql ];
|
|
||||||
|
|
||||||
# Project-specific environment variables
|
|
||||||
DATABASE_URL = "postgresql://localhost/mydb";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Shell Details
|
|
||||||
|
|
||||||
See individual shell files for detailed package lists and configuration:
|
|
||||||
|
|
||||||
- **Default Shell**: `shells/default.nix` - Nix development tools
|
|
||||||
- **Python Shell**: `shells/python.nix` - Python development environment
|
|
||||||
- **DevOps Shell**: `shells/devops.nix` - Infrastructure and cloud tools
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Setting Up Development Environment
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clone the repository
|
|
||||||
git clone https://code.m3ta.dev/m3tam3re/nixpkgs
|
|
||||||
cd m3ta-nixpkgs
|
|
||||||
|
|
||||||
# Enter development shell
|
|
||||||
nix develop
|
|
||||||
|
|
||||||
# Check flake validity
|
|
||||||
nix flake check
|
|
||||||
|
|
||||||
# Format code
|
|
||||||
nix fmt
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding a New Package
|
|
||||||
|
|
||||||
1. Create a new directory under `pkgs/`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
mkdir pkgs/my-package
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create `pkgs/my-package/default.nix`:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
lib,
|
|
||||||
stdenv,
|
|
||||||
fetchFromGitHub,
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation rec {
|
|
||||||
pname = "my-package";
|
|
||||||
version = "1.0.0";
|
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "owner";
|
|
||||||
repo = "repo";
|
|
||||||
rev = "v${version}";
|
|
||||||
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
|
|
||||||
};
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "Description of my package";
|
|
||||||
homepage = "https://github.com/owner/repo";
|
|
||||||
license = licenses.mit;
|
|
||||||
maintainers = with maintainers; [ ];
|
|
||||||
platforms = platforms.linux;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Add to `pkgs/default.nix`:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
# ... existing packages ...
|
|
||||||
my-package = pkgs.callPackage ./my-package {};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding a New NixOS Module
|
|
||||||
|
|
||||||
1. Create `modules/nixos/my-module.nix`
|
|
||||||
2. Add import to `modules/nixos/default.nix`
|
|
||||||
3. Update `flake.nix` to expose it:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
nixosModules = {
|
|
||||||
default = ./modules/nixos;
|
|
||||||
my-module = ./modules/nixos/my-module.nix;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding a New Home Manager Module
|
|
||||||
|
|
||||||
1. Create `modules/home-manager/my-module.nix`
|
|
||||||
2. Add to `modules/home-manager/default.nix`
|
|
||||||
3. Update `flake.nix` to expose it:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
homeManagerModules = {
|
|
||||||
default = import ./modules/home-manager;
|
|
||||||
my-module = import ./modules/home-manager/my-module.nix;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Port Management Module
|
|
||||||
|
|
||||||
**NEW!** Centrally manage service ports across your NixOS systems and Home Manager configurations with automatic host-specific overrides.
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
- ✅ **Centralized Configuration**: Define all ports in one place
|
|
||||||
- ✅ **Host-Specific Overrides**: Different ports for different machines (laptop, server, desktop)
|
|
||||||
- ✅ **Type Safety**: Full NixOS/Home Manager type system integration
|
|
||||||
- ✅ **Auto-Generated Files**: JSON exports and environment variables
|
|
||||||
- ✅ **Easy Integration**: Works with any service configuration
|
|
||||||
- ✅ **Conflict Prevention**: Avoid port conflicts across different hosts
|
|
||||||
|
|
||||||
### Quick Start - NixOS Module
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
imports = [ inputs.m3ta-nixpkgs.nixosModules.default ];
|
|
||||||
|
|
||||||
m3ta.ports = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
definitions = {
|
|
||||||
nginx = 80;
|
|
||||||
grafana = 3000;
|
|
||||||
ssh = 22;
|
|
||||||
prometheus = 9090;
|
|
||||||
};
|
|
||||||
|
|
||||||
hostOverrides = {
|
|
||||||
laptop = {
|
|
||||||
nginx = 8080; # Use non-privileged port
|
|
||||||
ssh = 2222;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Automatically uses system hostname
|
|
||||||
currentHost = config.networking.hostName;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use ports in your configuration
|
|
||||||
services.nginx.defaultHTTPListenPort = config.m3ta.ports.get "nginx";
|
|
||||||
services.openssh.ports = [ (config.m3ta.ports.get "ssh") ];
|
|
||||||
|
|
||||||
# Firewall with dynamic ports
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
(config.m3ta.ports.get "ssh")
|
|
||||||
(config.m3ta.ports.get "nginx")
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Quick Start - Home Manager Module
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
imports = [ inputs.m3ta-nixpkgs.homeManagerModules.default ];
|
|
||||||
|
|
||||||
m3ta.ports = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
definitions = {
|
|
||||||
vite-dev = 5173;
|
|
||||||
jupyter = 8888;
|
|
||||||
local-api = 8000;
|
|
||||||
};
|
|
||||||
|
|
||||||
hostOverrides = {
|
|
||||||
laptop = {
|
|
||||||
vite-dev = 5174;
|
|
||||||
jupyter = 9999;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
currentHost = "laptop";
|
|
||||||
|
|
||||||
# Auto-generate PORT_* environment variables
|
|
||||||
generateEnvVars = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use ports in your configuration
|
|
||||||
programs.bash.shellAliases = {
|
|
||||||
dev = "PORT=${toString (config.m3ta.ports.get "vite-dev")} npm run dev";
|
|
||||||
jupyter = "jupyter lab --port=${toString (config.m3ta.ports.get "jupyter")}";
|
|
||||||
};
|
|
||||||
|
|
||||||
home.sessionVariables = {
|
|
||||||
DEV_SERVER = "http://localhost:${toString (config.m3ta.ports.get "vite-dev")}";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Available Module Functions
|
|
||||||
|
|
||||||
- `config.m3ta.ports.get "service"` - Get port for service on current host
|
|
||||||
- `config.m3ta.ports.getForHost "host" "service"` - Get port for specific host
|
|
||||||
- `config.m3ta.ports.all` - All ports for current host (merged defaults + overrides)
|
|
||||||
- `config.m3ta.ports.allForHost "host"` - All ports for specific host
|
|
||||||
- `config.m3ta.ports.services` - List all defined service names
|
|
||||||
|
|
||||||
### Auto-Generated Files
|
|
||||||
|
|
||||||
**NixOS**: `/etc/m3ta/ports.json`
|
|
||||||
**Home Manager**: `~/.config/m3ta/ports.json`
|
|
||||||
|
|
||||||
These files contain all port configuration for easy inspection and external tool integration.
|
|
||||||
|
|
||||||
### Using the Library Directly
|
|
||||||
|
|
||||||
For advanced use cases, you can use the underlying library functions without the module:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
{
|
|
||||||
outputs = { nixpkgs, m3ta-nixpkgs, ... }: {
|
|
||||||
nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
|
|
||||||
modules = [
|
|
||||||
({ inputs, system, config, ... }: let
|
|
||||||
m3taLib = inputs.m3ta-nixpkgs.lib.${system};
|
|
||||||
|
|
||||||
myPorts = {
|
|
||||||
ports = { nginx = 80; grafana = 3000; };
|
|
||||||
hostPorts = { laptop = { nginx = 8080; }; };
|
|
||||||
};
|
|
||||||
|
|
||||||
portHelpers = m3taLib.ports.mkPortHelpers myPorts;
|
|
||||||
hostname = config.networking.hostName;
|
|
||||||
in {
|
|
||||||
services.nginx.port = portHelpers.getPort "nginx" hostname;
|
|
||||||
})
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
See library documentation:
|
|
||||||
|
|
||||||
- `lib/ports.nix` - Library source code with inline documentation
|
|
||||||
|
|
||||||
Example configurations:
|
|
||||||
|
|
||||||
- `examples/nixos-configuration.nix` - NixOS configuration example
|
|
||||||
- `examples/home-manager-standalone.nix` - Home Manager configuration example
|
|
||||||
|
|
||||||
## Available Packages
|
## Available Packages
|
||||||
|
|
||||||
@@ -515,6 +59,7 @@ Example configurations:
|
|||||||
| `code2prompt` | Convert code to prompts |
|
| `code2prompt` | Convert code to prompts |
|
||||||
| `hyprpaper-random` | Random wallpaper setter for Hyprpaper |
|
| `hyprpaper-random` | Random wallpaper setter for Hyprpaper |
|
||||||
| `launch-webapp` | Launch web applications |
|
| `launch-webapp` | Launch web applications |
|
||||||
|
| `mem0` | AI memory assistant with vector storage |
|
||||||
| `msty-studio` | Msty Studio application |
|
| `msty-studio` | Msty Studio application |
|
||||||
| `pomodoro-timer` | Pomodoro timer utility |
|
| `pomodoro-timer` | Pomodoro timer utility |
|
||||||
| `tuxedo-backlight` | Backlight control for Tuxedo laptops |
|
| `tuxedo-backlight` | Backlight control for Tuxedo laptops |
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
default = ./modules/nixos;
|
default = ./modules/nixos;
|
||||||
# Individual modules for selective imports
|
# Individual modules for selective imports
|
||||||
ports = ./modules/nixos/ports.nix;
|
ports = ./modules/nixos/ports.nix;
|
||||||
|
mem0 = ./modules/nixos/mem0.nix;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Home Manager modules - for user-level configuration
|
# Home Manager modules - for user-level configuration
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
# Add your custom modules here as imports or inline definitions
|
# Add your custom modules here as imports or inline definitions
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
|
./mem0.nix
|
||||||
./ports.nix
|
./ports.nix
|
||||||
# Example: ./my-service.nix
|
# Example: ./my-service.nix
|
||||||
# Add more module files here as you create them
|
# Add more module files here as you create them
|
||||||
|
|||||||
363
modules/nixos/mem0.nix
Normal file
363
modules/nixos/mem0.nix
Normal file
@@ -0,0 +1,363 @@
|
|||||||
|
# NixOS Module for Mem0 REST API Server
|
||||||
|
#
|
||||||
|
# This module provides a systemd service for the Mem0 REST API server,
|
||||||
|
# allowing you to run mem0 as a system service with configurable vector storage.
|
||||||
|
#
|
||||||
|
# Usage in your NixOS configuration:
|
||||||
|
#
|
||||||
|
# # In your flake.nix or configuration.nix:
|
||||||
|
# imports = [ inputs.m3ta-nixpkgs.nixosModules.default ];
|
||||||
|
#
|
||||||
|
# m3ta.mem0 = {
|
||||||
|
# enable = true;
|
||||||
|
# port = 8000;
|
||||||
|
# host = "127.0.0.1";
|
||||||
|
#
|
||||||
|
# # LLM Configuration
|
||||||
|
# llm = {
|
||||||
|
# provider = "openai";
|
||||||
|
# apiKeyFile = "/run/secrets/openai-api-key"; # Use agenix or sops-nix
|
||||||
|
# model = "gpt-4";
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# # Vector Storage Configuration
|
||||||
|
# vectorStore = {
|
||||||
|
# provider = "qdrant"; # or "chroma", "pinecone", etc.
|
||||||
|
# config = {
|
||||||
|
# host = "localhost";
|
||||||
|
# port = 6333;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# # Optional: Environment variables
|
||||||
|
# environmentFile = "/etc/mem0/environment";
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# Using with m3ta.ports (recommended):
|
||||||
|
#
|
||||||
|
# m3ta.ports = {
|
||||||
|
# enable = true;
|
||||||
|
# definitions = { mem0 = 8000; };
|
||||||
|
# hostOverrides.laptop = { mem0 = 8080; };
|
||||||
|
# currentHost = config.networking.hostName;
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
# m3ta.mem0 = {
|
||||||
|
# enable = true;
|
||||||
|
# port = config.m3ta.ports.get "mem0"; # Automatically uses host-specific port
|
||||||
|
# };
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
cfg = config.m3ta.mem0;
|
||||||
|
|
||||||
|
# Python environment with mem0
|
||||||
|
pythonEnv = pkgs.python3.withPackages (ps:
|
||||||
|
with ps; [
|
||||||
|
cfg.package
|
||||||
|
]);
|
||||||
|
|
||||||
|
# Convert vector store config to environment variables
|
||||||
|
vectorStoreEnv =
|
||||||
|
if cfg.vectorStore.provider == "qdrant"
|
||||||
|
then {
|
||||||
|
MEM0_VECTOR_PROVIDER = "qdrant";
|
||||||
|
QDRANT_HOST = cfg.vectorStore.config.host or "localhost";
|
||||||
|
QDRANT_PORT = toString (cfg.vectorStore.config.port or 6333);
|
||||||
|
QDRANT_COLLECTION = cfg.vectorStore.config.collection_name or "mem0_memories";
|
||||||
|
}
|
||||||
|
else if cfg.vectorStore.provider == "pgvector"
|
||||||
|
then {
|
||||||
|
MEM0_VECTOR_PROVIDER = "pgvector";
|
||||||
|
POSTGRES_HOST = cfg.vectorStore.config.host or "localhost";
|
||||||
|
POSTGRES_PORT = toString (cfg.vectorStore.config.port or 5432);
|
||||||
|
POSTGRES_DB = cfg.vectorStore.config.dbname or "postgres";
|
||||||
|
POSTGRES_USER = cfg.vectorStore.config.user or "postgres";
|
||||||
|
POSTGRES_PASSWORD = cfg.vectorStore.config.password or "postgres";
|
||||||
|
POSTGRES_COLLECTION = cfg.vectorStore.config.collection_name or "mem0_memories";
|
||||||
|
}
|
||||||
|
else if cfg.vectorStore.provider == "chroma"
|
||||||
|
then {
|
||||||
|
MEM0_VECTOR_PROVIDER = "chroma";
|
||||||
|
CHROMA_HOST = cfg.vectorStore.config.host or "localhost";
|
||||||
|
CHROMA_PORT = toString (cfg.vectorStore.config.port or 8000);
|
||||||
|
CHROMA_COLLECTION = cfg.vectorStore.config.collection_name or "mem0_memories";
|
||||||
|
}
|
||||||
|
else {};
|
||||||
|
|
||||||
|
# Start script that sets up environment and runs the server
|
||||||
|
startScript = pkgs.writeShellScript "mem0-start" ''
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Load environment file if specified
|
||||||
|
${optionalString (cfg.environmentFile != null) ''
|
||||||
|
if [ -f "${cfg.environmentFile}" ]; then
|
||||||
|
set -a
|
||||||
|
source "${cfg.environmentFile}"
|
||||||
|
set +a
|
||||||
|
fi
|
||||||
|
''}
|
||||||
|
|
||||||
|
# Load API key from file if specified
|
||||||
|
${optionalString (cfg.llm.apiKeyFile != null) ''
|
||||||
|
if [ -f "${cfg.llm.apiKeyFile}" ]; then
|
||||||
|
export OPENAI_API_KEY="$(cat ${cfg.llm.apiKeyFile})"
|
||||||
|
fi
|
||||||
|
''}
|
||||||
|
|
||||||
|
# Create state directory
|
||||||
|
mkdir -p ${cfg.stateDir}
|
||||||
|
cd ${cfg.stateDir}
|
||||||
|
|
||||||
|
# Run the server
|
||||||
|
exec ${pythonEnv}/bin/mem0-server
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
options.m3ta.mem0 = {
|
||||||
|
enable = mkEnableOption "Mem0 REST API server";
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.mem0;
|
||||||
|
defaultText = literalExpression "pkgs.mem0";
|
||||||
|
description = "The mem0 package to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
host = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "Host address to bind the server to.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 8000;
|
||||||
|
description = "Port to run the REST API server on.";
|
||||||
|
};
|
||||||
|
|
||||||
|
workers = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 1;
|
||||||
|
description = "Number of worker processes.";
|
||||||
|
};
|
||||||
|
|
||||||
|
logLevel = mkOption {
|
||||||
|
type = types.enum ["critical" "error" "warning" "info" "debug" "trace"];
|
||||||
|
default = "info";
|
||||||
|
description = "Logging level for the server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
stateDir = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "/var/lib/mem0";
|
||||||
|
description = "Directory to store mem0 data and state.";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "mem0";
|
||||||
|
description = "User account under which mem0 runs.";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "mem0";
|
||||||
|
description = "Group under which mem0 runs.";
|
||||||
|
};
|
||||||
|
|
||||||
|
environmentFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Environment file containing additional configuration.
|
||||||
|
This file should contain KEY=value pairs, one per line.
|
||||||
|
Useful for secrets that shouldn't be in the Nix store.
|
||||||
|
'';
|
||||||
|
example = "/etc/mem0/environment";
|
||||||
|
};
|
||||||
|
|
||||||
|
# LLM Configuration
|
||||||
|
llm = {
|
||||||
|
provider = mkOption {
|
||||||
|
type = types.enum ["openai" "anthropic" "azure" "groq" "together" "ollama" "litellm"];
|
||||||
|
default = "openai";
|
||||||
|
description = "LLM provider to use for memory operations.";
|
||||||
|
};
|
||||||
|
|
||||||
|
model = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "gpt-4o-mini";
|
||||||
|
description = "Model name to use for the LLM.";
|
||||||
|
};
|
||||||
|
|
||||||
|
apiKeyFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Path to file containing the API key for the LLM provider.
|
||||||
|
The file should contain only the API key.
|
||||||
|
This is more secure than putting the key in the Nix store.
|
||||||
|
'';
|
||||||
|
example = "/run/secrets/openai-api-key";
|
||||||
|
};
|
||||||
|
|
||||||
|
temperature = mkOption {
|
||||||
|
type = types.nullOr types.float;
|
||||||
|
default = null;
|
||||||
|
description = "Temperature parameter for LLM generation.";
|
||||||
|
};
|
||||||
|
|
||||||
|
maxTokens = mkOption {
|
||||||
|
type = types.nullOr types.int;
|
||||||
|
default = null;
|
||||||
|
description = "Maximum tokens for LLM generation.";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = "Additional LLM configuration options.";
|
||||||
|
example = {
|
||||||
|
top_p = 1.0;
|
||||||
|
frequency_penalty = 0.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Vector Store Configuration
|
||||||
|
vectorStore = {
|
||||||
|
provider = mkOption {
|
||||||
|
type = types.enum [
|
||||||
|
"qdrant"
|
||||||
|
"chroma"
|
||||||
|
"pinecone"
|
||||||
|
"weaviate"
|
||||||
|
"faiss"
|
||||||
|
"pgvector"
|
||||||
|
"redis"
|
||||||
|
"elasticsearch"
|
||||||
|
"milvus"
|
||||||
|
];
|
||||||
|
default = "qdrant";
|
||||||
|
description = "Vector database provider to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
Configuration for the vector store.
|
||||||
|
The structure depends on the provider.
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
host = "localhost";
|
||||||
|
port = 6333;
|
||||||
|
collection_name = "mem0_memories";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Embedder Configuration
|
||||||
|
embedder = {
|
||||||
|
provider = mkOption {
|
||||||
|
type = types.nullOr (types.enum ["openai" "huggingface" "ollama" "vertexai"]);
|
||||||
|
default = null;
|
||||||
|
description = "Embedding model provider. If null, uses default.";
|
||||||
|
};
|
||||||
|
|
||||||
|
model = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Embedding model name to use.";
|
||||||
|
example = "text-embedding-3-small";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = "Configuration for the embedder.";
|
||||||
|
example = {
|
||||||
|
model = "text-embedding-3-small";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
# Create user and group
|
||||||
|
users.users.${cfg.user} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = cfg.group;
|
||||||
|
description = "Mem0 service user";
|
||||||
|
home = cfg.stateDir;
|
||||||
|
createHome = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.${cfg.group} = {};
|
||||||
|
|
||||||
|
# Systemd service
|
||||||
|
systemd.services.mem0 = {
|
||||||
|
description = "Mem0 REST API Server";
|
||||||
|
after = ["network.target"];
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = cfg.user;
|
||||||
|
Group = cfg.group;
|
||||||
|
ExecStart = startScript;
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = "5s";
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ProtectHome = true;
|
||||||
|
ReadWritePaths = [cfg.stateDir];
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = false; # Python needs this
|
||||||
|
RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
|
||||||
|
};
|
||||||
|
|
||||||
|
environment =
|
||||||
|
{
|
||||||
|
PYTHONUNBUFFERED = "1";
|
||||||
|
MEM0_HOST = cfg.host;
|
||||||
|
MEM0_PORT = toString cfg.port;
|
||||||
|
MEM0_LLM_PROVIDER = cfg.llm.provider;
|
||||||
|
MEM0_LLM_MODEL = cfg.llm.model;
|
||||||
|
MEM0_HISTORY_DB_PATH = "${cfg.stateDir}/history.db";
|
||||||
|
MEM0_WORKERS = toString cfg.workers;
|
||||||
|
MEM0_LOG_LEVEL = cfg.logLevel;
|
||||||
|
}
|
||||||
|
// optionalAttrs (cfg.llm.temperature != null) {
|
||||||
|
MEM0_LLM_TEMPERATURE = toString cfg.llm.temperature;
|
||||||
|
}
|
||||||
|
// optionalAttrs (cfg.llm.extraConfig != {}) {
|
||||||
|
MEM0_LLM_EXTRA_CONFIG = builtins.toJSON cfg.llm.extraConfig;
|
||||||
|
}
|
||||||
|
// optionalAttrs (cfg.embedder.provider != null) {
|
||||||
|
MEM0_EMBEDDER_PROVIDER = cfg.embedder.provider;
|
||||||
|
}
|
||||||
|
// optionalAttrs (cfg.embedder.model != null) {
|
||||||
|
MEM0_EMBEDDER_MODEL = cfg.embedder.model;
|
||||||
|
}
|
||||||
|
// vectorStoreEnv;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Open firewall port if binding to non-localhost
|
||||||
|
networking.firewall.allowedTCPPorts = mkIf (cfg.host != "127.0.0.1" && cfg.host != "localhost") [cfg.port];
|
||||||
|
};
|
||||||
|
}
|
||||||
33
pkgs/AGENTS.md
Normal file
33
pkgs/AGENTS.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# pkgs/ AGENTS.md
|
||||||
|
|
||||||
|
## OVERVIEW
|
||||||
|
Custom package registry using `callPackage` pattern for flake-wide availability.
|
||||||
|
|
||||||
|
## STRUCTURE
|
||||||
|
- `default.nix`: Central registry (entry point for overlays)
|
||||||
|
- `code2prompt/`: Rust package
|
||||||
|
- `hyprpaper-random/`: Bash script
|
||||||
|
- `launch-webapp/`: Webapp wrapper
|
||||||
|
- `mem0/`: Python package + custom `server.py`
|
||||||
|
- `msty-studio/`: AppImage wrapper
|
||||||
|
- `pomodoro-timer/`: Timer utility
|
||||||
|
- `tuxedo-backlight/`: Hardware control
|
||||||
|
- `zellij-ps/`: Gitea-hosted package
|
||||||
|
|
||||||
|
## WHERE TO LOOK
|
||||||
|
- **Register new pkg**: Add entry to `pkgs/default.nix` attribute set
|
||||||
|
- **Modify pkg**: Edit `pkgs/<name>/default.nix` (version, hash, deps)
|
||||||
|
- **Check visibility**: `nix flake show` (uses `pkgs/default.nix` via `overlays/default.nix`)
|
||||||
|
- **Add scripts**: Place alongside `default.nix` in package folder (e.g., `mem0/server.py`)
|
||||||
|
|
||||||
|
## CONVENTIONS
|
||||||
|
- **CallPackage**: Always use `pkgs.callPackage ./dir {}` in registry
|
||||||
|
- **Dir == Attr**: Package directory name MUST match its registry attribute
|
||||||
|
- **Path literals**: Reference local assets using `./file` within derivations
|
||||||
|
- **Self-contained**: Keep all package-specific files in their own directory
|
||||||
|
|
||||||
|
## ANTI-PATTERNS
|
||||||
|
- **Orphaned dirs**: Creating `pkgs/new-pkg/` without updating `pkgs/default.nix`
|
||||||
|
- **Direct flake imports**: Importing packages in `flake.nix` instead of through the registry
|
||||||
|
- **Implicit deps**: Not declaring dependencies in the package function arguments
|
||||||
|
- **Non-derivations**: Placing NixOS/HM modules here (use `modules/` instead)
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
code2prompt = pkgs.callPackage ./code2prompt {};
|
code2prompt = pkgs.callPackage ./code2prompt {};
|
||||||
hyprpaper-random = pkgs.callPackage ./hyprpaper-random {};
|
hyprpaper-random = pkgs.callPackage ./hyprpaper-random {};
|
||||||
launch-webapp = pkgs.callPackage ./launch-webapp {};
|
launch-webapp = pkgs.callPackage ./launch-webapp {};
|
||||||
|
mem0 = pkgs.callPackage ./mem0 {};
|
||||||
msty-studio = pkgs.callPackage ./msty-studio {};
|
msty-studio = pkgs.callPackage ./msty-studio {};
|
||||||
pomodoro-timer = pkgs.callPackage ./pomodoro-timer {};
|
pomodoro-timer = pkgs.callPackage ./pomodoro-timer {};
|
||||||
tuxedo-backlight = pkgs.callPackage ./tuxedo-backlight {};
|
tuxedo-backlight = pkgs.callPackage ./tuxedo-backlight {};
|
||||||
|
|||||||
99
pkgs/mem0/default.nix
Normal file
99
pkgs/mem0/default.nix
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
python3,
|
||||||
|
fetchFromGitHub,
|
||||||
|
}:
|
||||||
|
python3.pkgs.buildPythonPackage rec {
|
||||||
|
pname = "mem0ai";
|
||||||
|
version = "1.0.0";
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "mem0ai";
|
||||||
|
repo = "mem0";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-DluzIhwL/GanqtRSMW7ax+OVc2kZjbwQ0lpPCQFnD58=";
|
||||||
|
};
|
||||||
|
|
||||||
|
# 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
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Long-term memory layer for AI agents with REST API support";
|
||||||
|
longDescription = ''
|
||||||
|
Mem0 provides a sophisticated memory layer for AI applications, offering:
|
||||||
|
- Memory management for AI agents (add, search, update, delete)
|
||||||
|
- REST API server for easy integration
|
||||||
|
- Support for multiple vector storage backends (Qdrant, Chroma, etc.)
|
||||||
|
- Graph memory capabilities
|
||||||
|
- Multi-modal support
|
||||||
|
- Configurable LLM and embedding models
|
||||||
|
'';
|
||||||
|
homepage = "https://github.com/mem0ai/mem0";
|
||||||
|
changelog = "https://github.com/mem0ai/mem0/releases/tag/v${version}";
|
||||||
|
license = licenses.asl20;
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
301
pkgs/mem0/server.py
Normal file
301
pkgs/mem0/server.py
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Mem0 REST API Server
|
||||||
|
A FastAPI-based REST server for mem0 memory operations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
from fastapi import FastAPI, HTTPException
|
||||||
|
from fastapi.responses import JSONResponse, RedirectResponse
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from mem0 import Memory
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
||||||
|
|
||||||
|
|
||||||
|
# Configuration from environment variables
|
||||||
|
def get_config_from_env() -> Dict[str, Any]:
|
||||||
|
"""Build mem0 configuration from environment variables."""
|
||||||
|
config = {"version": "v1.1"}
|
||||||
|
|
||||||
|
# Vector store configuration
|
||||||
|
vector_provider = os.environ.get("MEM0_VECTOR_PROVIDER", "qdrant")
|
||||||
|
config["vector_store"] = {"provider": vector_provider}
|
||||||
|
|
||||||
|
if vector_provider == "qdrant":
|
||||||
|
config["vector_store"]["config"] = {
|
||||||
|
"host": os.environ.get("QDRANT_HOST", "localhost"),
|
||||||
|
"port": int(os.environ.get("QDRANT_PORT", "6333")),
|
||||||
|
"collection_name": os.environ.get("QDRANT_COLLECTION", "mem0_memories"),
|
||||||
|
}
|
||||||
|
elif vector_provider == "pgvector":
|
||||||
|
config["vector_store"]["config"] = {
|
||||||
|
"host": os.environ.get("POSTGRES_HOST", "localhost"),
|
||||||
|
"port": int(os.environ.get("POSTGRES_PORT", "5432")),
|
||||||
|
"dbname": os.environ.get("POSTGRES_DB", "postgres"),
|
||||||
|
"user": os.environ.get("POSTGRES_USER", "postgres"),
|
||||||
|
"password": os.environ.get("POSTGRES_PASSWORD", "postgres"),
|
||||||
|
"collection_name": os.environ.get("POSTGRES_COLLECTION", "mem0_memories"),
|
||||||
|
}
|
||||||
|
elif vector_provider == "chroma":
|
||||||
|
config["vector_store"]["config"] = {
|
||||||
|
"host": os.environ.get("CHROMA_HOST", "localhost"),
|
||||||
|
"port": int(os.environ.get("CHROMA_PORT", "8000")),
|
||||||
|
"collection_name": os.environ.get("CHROMA_COLLECTION", "mem0_memories"),
|
||||||
|
}
|
||||||
|
|
||||||
|
# LLM configuration
|
||||||
|
llm_provider = os.environ.get("MEM0_LLM_PROVIDER", "openai")
|
||||||
|
config["llm"] = {
|
||||||
|
"provider": llm_provider,
|
||||||
|
"config": {
|
||||||
|
"model": os.environ.get("MEM0_LLM_MODEL", "gpt-4o-mini"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Temperature: only include if set (null means use provider default)
|
||||||
|
temperature = os.environ.get("MEM0_LLM_TEMPERATURE")
|
||||||
|
if temperature is not None:
|
||||||
|
config["llm"]["config"]["temperature"] = float(temperature)
|
||||||
|
|
||||||
|
# Extra config: merge JSON env var if provided
|
||||||
|
extra_config_json = os.environ.get("MEM0_LLM_EXTRA_CONFIG")
|
||||||
|
if extra_config_json:
|
||||||
|
import json
|
||||||
|
try:
|
||||||
|
extra_config = json.loads(extra_config_json)
|
||||||
|
config["llm"]["config"].update(extra_config)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
logging.warning(f"Failed to parse MEM0_LLM_EXTRA_CONFIG: {extra_config_json}")
|
||||||
|
|
||||||
|
# Add API key if available
|
||||||
|
if llm_provider == "openai":
|
||||||
|
api_key = os.environ.get("OPENAI_API_KEY")
|
||||||
|
if api_key:
|
||||||
|
config["llm"]["config"]["api_key"] = api_key
|
||||||
|
|
||||||
|
# Embedder configuration
|
||||||
|
embedder_provider = os.environ.get("MEM0_EMBEDDER_PROVIDER", "openai")
|
||||||
|
config["embedder"] = {
|
||||||
|
"provider": embedder_provider,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Embedder model: only include if provider is set
|
||||||
|
if embedder_provider:
|
||||||
|
embedder_config = {}
|
||||||
|
embedder_model = os.environ.get("MEM0_EMBEDDER_MODEL")
|
||||||
|
if embedder_model:
|
||||||
|
embedder_config["model"] = embedder_model
|
||||||
|
config["embedder"]["config"] = embedder_config
|
||||||
|
|
||||||
|
if embedder_provider == "openai":
|
||||||
|
api_key = os.environ.get("OPENAI_API_KEY")
|
||||||
|
if api_key:
|
||||||
|
config["embedder"]["config"]["api_key"] = api_key
|
||||||
|
|
||||||
|
# History DB path
|
||||||
|
history_db_path = os.environ.get("MEM0_HISTORY_DB_PATH", "/var/lib/mem0/history.db")
|
||||||
|
config["history_db_path"] = history_db_path
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
# Initialize Memory instance
|
||||||
|
try:
|
||||||
|
config = get_config_from_env()
|
||||||
|
logging.info(f"Initializing mem0 with config: {config}")
|
||||||
|
|
||||||
|
# Validate API key is set for OpenAI provider
|
||||||
|
if config.get("llm", {}).get("provider") == "openai":
|
||||||
|
if not config.get("llm", {}).get("config", {}).get("api_key"):
|
||||||
|
logging.error("OPENAI_API_KEY environment variable is required but not set.")
|
||||||
|
logging.error("Please set OPENAI_API_KEY environment variable or configure apiKeyFile in NixOS module.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
MEMORY_INSTANCE = Memory.from_config(config)
|
||||||
|
logging.info("Memory instance initialized successfully")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Failed to initialize Memory: {e}")
|
||||||
|
logging.error("Please check your configuration and ensure all required services are running.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI(
|
||||||
|
title="Mem0 REST API",
|
||||||
|
description="A REST API for managing and searching memories for your AI Agents and Apps.",
|
||||||
|
version="1.0.0",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Message(BaseModel):
|
||||||
|
role: str = Field(..., description="Role of the message (user or assistant).")
|
||||||
|
content: str = Field(..., description="Message content.")
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryCreate(BaseModel):
|
||||||
|
messages: List[Message] = Field(..., description="List of messages to store.")
|
||||||
|
user_id: Optional[str] = None
|
||||||
|
agent_id: Optional[str] = None
|
||||||
|
run_id: Optional[str] = None
|
||||||
|
metadata: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
|
|
||||||
|
class SearchRequest(BaseModel):
|
||||||
|
query: str = Field(..., description="Search query.")
|
||||||
|
user_id: Optional[str] = None
|
||||||
|
run_id: Optional[str] = None
|
||||||
|
agent_id: Optional[str] = None
|
||||||
|
filters: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/", summary="Redirect to documentation", include_in_schema=False)
|
||||||
|
def home():
|
||||||
|
"""Redirect to the OpenAPI documentation."""
|
||||||
|
return RedirectResponse(url="/docs")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/health", summary="Health check")
|
||||||
|
def health():
|
||||||
|
"""Check if the server is running."""
|
||||||
|
return {"status": "healthy", "service": "mem0-api"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/configure", summary="Configure Mem0")
|
||||||
|
def set_config(config: Dict[str, Any]):
|
||||||
|
"""Set memory configuration."""
|
||||||
|
global MEMORY_INSTANCE
|
||||||
|
MEMORY_INSTANCE = Memory.from_config(config)
|
||||||
|
return {"message": "Configuration set successfully"}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/memories", summary="Create memories")
|
||||||
|
def add_memory(memory_create: MemoryCreate):
|
||||||
|
"""Store new memories."""
|
||||||
|
if not any([memory_create.user_id, memory_create.agent_id, memory_create.run_id]):
|
||||||
|
raise HTTPException(status_code=400, detail="At least one identifier (user_id, agent_id, run_id) is required.")
|
||||||
|
|
||||||
|
params = {k: v for k, v in memory_create.model_dump().items() if v is not None and k != "messages"}
|
||||||
|
try:
|
||||||
|
response = MEMORY_INSTANCE.add(messages=[m.model_dump() for m in memory_create.messages], **params)
|
||||||
|
return JSONResponse(content=response)
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in add_memory:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/memories", summary="Get memories")
|
||||||
|
def get_all_memories(
|
||||||
|
user_id: Optional[str] = None,
|
||||||
|
run_id: Optional[str] = None,
|
||||||
|
agent_id: Optional[str] = None,
|
||||||
|
):
|
||||||
|
"""Retrieve stored memories."""
|
||||||
|
if not any([user_id, run_id, agent_id]):
|
||||||
|
raise HTTPException(status_code=400, detail="At least one identifier is required.")
|
||||||
|
try:
|
||||||
|
params = {
|
||||||
|
k: v for k, v in {"user_id": user_id, "run_id": run_id, "agent_id": agent_id}.items() if v is not None
|
||||||
|
}
|
||||||
|
return MEMORY_INSTANCE.get_all(**params)
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in get_all_memories:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/memories/{memory_id}", summary="Get a memory")
|
||||||
|
def get_memory(memory_id: str):
|
||||||
|
"""Retrieve a specific memory by ID."""
|
||||||
|
try:
|
||||||
|
return MEMORY_INSTANCE.get(memory_id)
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in get_memory:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/search", summary="Search memories")
|
||||||
|
def search_memories(search_req: SearchRequest):
|
||||||
|
"""Search for memories based on a query."""
|
||||||
|
try:
|
||||||
|
params = {k: v for k, v in search_req.model_dump().items() if v is not None and k != "query"}
|
||||||
|
return MEMORY_INSTANCE.search(query=search_req.query, **params)
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in search_memories:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.put("/memories/{memory_id}", summary="Update a memory")
|
||||||
|
def update_memory(memory_id: str, updated_memory: Dict[str, Any]):
|
||||||
|
"""Update an existing memory with new content."""
|
||||||
|
try:
|
||||||
|
return MEMORY_INSTANCE.update(memory_id=memory_id, data=updated_memory)
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in update_memory:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/memories/{memory_id}/history", summary="Get memory history")
|
||||||
|
def memory_history(memory_id: str):
|
||||||
|
"""Retrieve memory history."""
|
||||||
|
try:
|
||||||
|
return MEMORY_INSTANCE.history(memory_id=memory_id)
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in memory_history:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.delete("/memories/{memory_id}", summary="Delete a memory")
|
||||||
|
def delete_memory(memory_id: str):
|
||||||
|
"""Delete a specific memory by ID."""
|
||||||
|
try:
|
||||||
|
MEMORY_INSTANCE.delete(memory_id=memory_id)
|
||||||
|
return {"message": "Memory deleted successfully"}
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in delete_memory:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.delete("/memories", summary="Delete all memories")
|
||||||
|
def delete_all_memories(
|
||||||
|
user_id: Optional[str] = None,
|
||||||
|
run_id: Optional[str] = None,
|
||||||
|
agent_id: Optional[str] = None,
|
||||||
|
):
|
||||||
|
"""Delete all memories for a given identifier."""
|
||||||
|
if not any([user_id, run_id, agent_id]):
|
||||||
|
raise HTTPException(status_code=400, detail="At least one identifier is required.")
|
||||||
|
try:
|
||||||
|
params = {
|
||||||
|
k: v for k, v in {"user_id": user_id, "run_id": run_id, "agent_id": agent_id}.items() if v is not None
|
||||||
|
}
|
||||||
|
MEMORY_INSTANCE.delete_all(**params)
|
||||||
|
return {"message": "All relevant memories deleted"}
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in delete_all_memories:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/reset", summary="Reset all memories")
|
||||||
|
def reset_memory():
|
||||||
|
"""Completely reset stored memories."""
|
||||||
|
try:
|
||||||
|
MEMORY_INSTANCE.reset()
|
||||||
|
return {"message": "All memories reset"}
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception("Error in reset_memory:")
|
||||||
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
|
||||||
|
host = os.environ.get("MEM0_HOST", "127.0.0.1")
|
||||||
|
port = int(os.environ.get("MEM0_PORT", "8000"))
|
||||||
|
workers = int(os.environ.get("MEM0_WORKERS", "1"))
|
||||||
|
log_level = os.environ.get("MEM0_LOG_LEVEL", "info")
|
||||||
|
|
||||||
|
uvicorn.run(app, host=host, port=port, workers=workers, log_level=log_level)
|
||||||
Reference in New Issue
Block a user