{"id":50146733,"url":"https://github.com/mmmarcinho/aizo","last_synced_at":"2026-05-24T05:08:36.302Z","repository":{"id":356328386,"uuid":"1228107148","full_name":"MMMarcinho/aizo","owner":"MMMarcinho","description":"Lightweight, high-performance preference memory system for AI agents","archived":false,"fork":false,"pushed_at":"2026-05-16T06:23:59.000Z","size":191,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-16T08:43:54.087Z","etag":null,"topics":["agent","agent-memory","lightweight","memory","memory-management","preferences"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MMMarcinho.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-03T15:52:29.000Z","updated_at":"2026-05-16T06:24:03.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/MMMarcinho/aizo","commit_stats":null,"previous_names":["mmmarcinho/aizo"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/MMMarcinho/aizo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMMarcinho%2Faizo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMMarcinho%2Faizo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMMarcinho%2Faizo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMMarcinho%2Faizo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MMMarcinho","download_url":"https://codeload.github.com/MMMarcinho/aizo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MMMarcinho%2Faizo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33365879,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-21T12:23:38.849Z","status":"online","status_checked_at":"2026-05-22T02:00:06.671Z","response_time":265,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","agent-memory","lightweight","memory","memory-management","preferences"],"created_at":"2026-05-24T05:08:22.692Z","updated_at":"2026-05-24T05:08:36.293Z","avatar_url":"https://github.com/MMMarcinho.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# aizo 爱憎\n\n![aizo — preference memory for AI agents](assets/aizo-hero.png)\n\n[中文文档](README.zh.md)\n\n**aizo** (爱憎, *ài zēng*, \"love and hate\") is a lightweight, high-performance preference memory system for AI agents, built entirely in Rust.\n\nIt mimics human cognitive memory: rather than storing full conversation transcripts, it continuously **extracts, quantifies, decays, and recalls** a user's stable preferences, aversions, habits, communication styles, and hard limits from interaction history. The result is a compact, numerically-weighted personality profile that any agent can query in milliseconds.\n\n---\n\n## How it fits together\n\naizo is designed around two complementary patterns:\n\n```\n╔══════════════════════════════════════════════════════════════════════╗\n║  1. In-session  (reactive — detects specific emotions in real time)  ║\n╚══════════════════════════════════════════════════════════════════════╝\n\n   user ──► agent ─────── aizo add ──────────────────┐\n                                                     ▼\n                       CLAUDE.md ◄── contributes ── local SQLite\n                                                (user preference)\n\n\n╔══════════════════════════════════════════════════════════════════════╗\n║  2. Just-in-time recall  (on-demand — pulls relevant prefs per task) ║\n╚══════════════════════════════════════════════════════════════════════╝\n\n   agent gets task ──► aizo recall --scenario coding ──► session context\n                                                              │\n                                                              ▼\n                                                  generate with preferences\n```\n\n**Loop 1 — In-session:** the agent detects a strong preference signal mid-conversation\n(praise, complaint, explicit rule) and calls `aizo add` immediately. Key preferences\nthat should persist across all sessions are written into `CLAUDE.md` or `MEMORY.md`.\n\n**Loop 2 — Just-in-time recall:** not all preferences belong in persistent context files.\nThe agent classifies each incoming task into a scenario, calls `aizo recall --scenario \u003cX\u003e`,\nand injects only the relevant preferences into the current session context. This keeps\nthe agent's base context lean while giving it access to the full preference profile —\njust like human working memory.\n\nFor batch analysis of historical sessions to discover new preferences, see SOP 6 in\n`skills/aizo-sop.md` — this is a skill-level concern, not a built-in aizo command.\n\n---\n\n## Core design\n\n```\nagent observation  (praise, complaint, rule, habit)\n       │\n       ▼\n  aizo add  { item, base_score 0–10, keywords, scenarios }\n       │  smooth merge  (old×0.4 + new×0.6)\n       ▼\n  SQLite (~/.aizo/preferences.db)\n       │\n       ▼\n  effective_weight = s · d(t)^α   (score-modulated decay)\n       │  keyword / score-band / scenario recall\n       ▼\n  agent reads profile → personalizes response\n```\n\n### Scoring formula\n\nAll scoring logic lives in `src/scoring/mod.rs`. Every preference entry carries three computed fields, derived at read time from its `base_score` and `last_seen` timestamp.\n\n**Step 1 — Decay coefficient d(t)**\n\n$$d(t) = \\phi + (1 - \\phi) \\cdot e^{-\\lambda t}, \\quad \\lambda = \\frac{\\ln 2}{t_{1/2}}$$\n\nwhere t is days since `last_seen`, t½ (half-life) is the configured half-life, and φ (floor) is the minimum decay.\n\n**Step 2 — Score-dependent exponent α**\n\n$$\\alpha = \\frac{10 - s}{10}$$\n\nHigher score → smaller α → decay has less effect. A score-10 preference (α = 0) is fully decay-resistant; a score-0 entry (α = 1) decays at full speed.\n\n**Step 3 — Effective weight w**\n\n$$w = s \\cdot d(t)^{\\alpha}$$\n\nExpanding into a single expression:\n\n$$\\boxed{w = s \\cdot \\left[\\phi + (1-\\phi) \\cdot e^{-\\lambda t}\\right]^{\\frac{10-s}{10}}}$$\n\n**Boundary behaviour**\n\n| Score s | α | Decay effect | Interpretation |\n|---|---|---|---|\n| 10 | 0.0 | None (d⁰ = 1) | Core value, never fades |\n| 7  | 0.3 | Slight | Strong preference, slow fade |\n| 5  | 0.5 | Moderate | Neutral habit, fades at half speed |\n| 1  | 0.9 | Near-full | Weak aversion, fades quickly |\n| 0  | 1.0 | Full (w = 0) | Absolute zero |\n\nEntries are **never hard-deleted by decay** — they sink toward the floor and persist as weak long-term memory. Use `aizo recall --type taboo` to surface hard limits regardless of effective weight.\n\n### Score smoothing\n\nWhen the same entry is seen again across sessions:\n```\nnew_base_score = old_base_score × 0.4 + incoming_score × 0.6\n```\n`last_seen` is always refreshed, which resets the decay clock.\n\n---\n\n## Installation\n\n```bash\n# Cargo (recommended)\ncargo install aizo\n\n# npm / npx\nnpm install -g aizo\nnpx aizo top 10\n\n# From source (Rust ≥ 1.70)\ngit clone https://github.com/mmmarcinho/aizo\ncd aizo \u0026\u0026 cargo build --release\ncp target/release/aizo /usr/local/bin/aizo\n```\n\n### Configuration\n\nSet env vars in `~/.aizo/.env` (user-wide) or `./.env` (per-project). Shell env always wins.\n\n```bash\n# Only AIZO_DB_PATH is needed for basic use (add/recall/top/show)\nexport AIZO_DB_PATH=~/.aizo/preferences.db\n```\n\n| Variable | Default | Description |\n|---|---|---|\n| `AIZO_DB_PATH` | `~/.aizo/preferences.db` | SQLite database path |\n\n---\n\n## CLI reference\n\n```\naizo [--db \u003cpath\u003e] \u003cCOMMAND\u003e\n```\n\n| Command | Description |\n|---|---|\n| `recall [query]` | Keyword + score-range recall — **primary agent call** |\n| `top [N]` | Top-N entries by effective weight (read-only, default 10) |\n| `show` | Full profile sorted by effective weight (read-only) |\n| `add \u003citem\u003e \u003creason\u003e` | Manually add or update a preference |\n| `update \u003citem\u003e` | Update fields on an existing entry (item, reason, score, keywords, scenarios) |\n| `apply \u003cid…\u003e` | Mark recalled entries as actually used; refreshes decay with a 12-hour cooldown |\n| `touch \u003citem…\u003e` | Reset decay clock by item label, subject to the same 12-hour cooldown |\n| `remove \u003citem…\u003e` | Hard-remove an entry |\n| `keywords` | List all stored keywords with entry counts |\n| `scenarios` | List all scenarios with entry counts and configured keywords |\n| `clear` | Wipe entire preference profile |\n| `info` | DB path, score distribution, env config, decay settings |\n| `config show/set-half-life/set-floor` | Get or set decay parameters |\n\n**`recall` flags:**\n\n| Flag | Description |\n|---|---|\n| `--type/-t \u003ctypes\u003e` | Score-range filter, comma-separated: `preference`, `style`, `habit`, `aversion`, `taboo` |\n| `--limit/-l \u003cN\u003e` | Cap results after sorting by effective weight |\n| `--scenario \u003cname\u003e` | Scenario-tagged recall + keyword expansion from `~/.aizo/scenarios.yaml` |\n| `--min-score \u003cN\u003e` | Minimum `base_score` threshold (0.0–10.0); clamps band lower bounds |\n| `--touch` | Refresh matched entries, subject to the 12-hour cooldown; recall is read-only by default |\n| `--no-touch` | Deprecated no-op kept for older scripts |\n| `--json` | Output raw JSON instead of human-readable text |\n\n**`top` flags:** `--type/-t`, `--scenario`, `--json`. Read-only — never touches `last_seen`.\n\n**`show` flags:** `--json` only. Read-only — never touches `last_seen`.\n\n### Score guide\n\nThere is no `category` field. The `base_score` is the only dimension that matters:\n\n| Score | Meaning | `--type` alias |\n|---|---|---|\n| 0–1.5 | Hard limit / must never do | `taboo` |\n| 1.6–4 | Clear dislike | `aversion` |\n| 4–6.5 | Neutral habit or weak pattern | `habit` |\n| 6.5–10 | Style / communication preference | `style` |\n| 7–10 | Clear preference | `preference` |\n\nUse `--type` on `recall` and `top` to filter by score range. Comma-separate for multi-type:\n\n```bash\naizo recall code --type preference,habit,style,taboo\naizo recall --type taboo               # all hard limits, no keyword needed\naizo top 5 --type preference\n```\n\nUse keywords (`--keywords` on add, or `aizo update --keywords`) to add any taxonomy you want.\n\n### Examples\n\n```bash\n# Agent recalls preferences before generating\naizo top 5\naizo recall \"code style\"\n\n# Scenario-aware recall for coding tasks (expands to ~10 coding keywords)\naizo recall --scenario coding --type preference,style,habit,taboo --limit 20\n\n# Mark only the preferences the agent actually used\naizo apply 3 8 12\n\n# Type-only recall (no keyword — returns all entries in that score range)\naizo recall --type taboo                        # all hard limits\naizo recall code --type preference --limit 10   # top coding preferences\naizo recall code --type preference,habit --limit 20  # multiple types\n\n# Custom minimum score threshold\naizo recall --scenario coding --min-score 5.0 --limit 20\n\n# Inspect full profile or top-N\naizo show\naizo top 20 --scenario coding --json\n\n# Manual entries — score encodes sentiment\naizo add \"concise code\"     \"Always asks for shorter implementations\"  --score 9.0\naizo add \"verbose comments\" \"Complained about over-documented code\"    --score 1.5\naizo add \"emojis in output\" \"Explicitly said never use emojis\"         --score 0.5\naizo add \"uses dark mode\"   \"Mentioned dark theme in every UI session\" --score 5.0 --scenarios coding\n\n# Update an existing entry\naizo update \"concise code\" --score 8.5 --keywords brevity,minimal,short\naizo update \"verbose comments\" --scenarios coding,writing\n\n# Tune decay (default: half-life 30d, floor 0.1)\naizo config set-half-life 14\naizo config set-floor 0.05\n\n# Stats\naizo info\n```\n\n---\n\n## Entry format\n\n```json\n{\n  \"id\": 1,\n  \"item\": \"concise code\",\n  \"reason\": \"Always asks for shorter implementations with no fluff.\",\n  \"keywords\": [\"brevity\", \"minimal\", \"short\", \"lean\"],\n  \"base_score\": 9.0,\n  \"source\": \"analysis\",\n  \"added_at\": \"2026-05-07T14:00:00+00:00\",\n  \"last_seen\": \"2026-05-07T15:30:00+00:00\",\n  \"score_exponent\": 0.1,\n  \"decay_coefficient\": 0.87,\n  \"effective_weight\": 7.83\n}\n```\n\n---\n\n## Database schema\n\n```sql\nCREATE TABLE preferences (\n    id          INTEGER PRIMARY KEY AUTOINCREMENT,\n    item        TEXT    NOT NULL,\n    reason      TEXT    NOT NULL,\n    keywords    TEXT    NOT NULL DEFAULT '',    -- comma-separated synonym tags\n    base_score  REAL    NOT NULL DEFAULT 5.0,   -- 0-10\n    source      TEXT    NOT NULL DEFAULT 'manual',\n    added_at    TEXT    NOT NULL,\n    last_seen   TEXT    NOT NULL,               -- resets decay clock on each reinforcement\n    touch_count INTEGER NOT NULL DEFAULT 0\n);\n-- UNIQUE on LOWER(item)\n\nCREATE TABLE decay_config (\n    id              INTEGER PRIMARY KEY CHECK(id = 1),\n    half_life_days  REAL    NOT NULL DEFAULT 30.0,\n    floor           REAL    NOT NULL DEFAULT 0.1\n);\n```\n\n---\n\n## Agent integration\n\nAny agent can call aizo as a subprocess — no embedding, no vector index, no runtime:\n\n```python\nimport subprocess, json\n\ndef recall_scenario(scenario: str, min_score: float = 3.0) -\u003e list[dict]:\n    \"\"\"Just-in-time recall for a specific task scenario.\"\"\"\n    return json.loads(subprocess.check_output(\n        [\"aizo\", \"recall\", \"--scenario\", scenario,\n         \"--type\", \"preference,style,habit,taboo\",\n         \"--min-score\", str(min_score), \"--limit\", \"20\", \"--json\"]\n    ))\n\ndef top_preferences(n: int = 10) -\u003e list[dict]:\n    return json.loads(subprocess.check_output([\"aizo\", \"top\", str(n), \"--json\"]))\n\ndef apply_preferences(ids: list[int]) -\u003e None:\n    \"\"\"Call after the agent actually used specific recalled preferences.\"\"\"\n    if ids:\n        subprocess.check_call([\"aizo\", \"apply\", *map(str, ids)])\n\n# Just-in-time: before coding, recall coding-specific preferences\ncoding_prefs = recall_scenario(\"coding\")\n# Inject into session context — don't write to disk\ncontext = f\"[Coding preferences]\\n{json.dumps(coding_prefs, indent=2)}\"\n# After generation, apply only the ids that shaped the response.\napply_preferences([p[\"id\"] for p in coding_prefs[:3]])\n\n# Before writing a document, recall writing preferences\nwriting_prefs = recall_scenario(\"writing\")\n```\n\nOr configure `AIZO_DB_PATH` per-project to maintain separate profiles:\n\n```bash\nexport AIZO_DB_PATH=./project-prefs.db\naizo show\n```\n\n### Just-in-time scenario recall\n\nNot all preferences belong in persistent context files like `CLAUDE.md` or `MEMORY.md` —\nthose files would grow unboundedly. Instead, use **scenario-based recall** to pull relevant\npreferences on demand, right when the agent receives a task:\n\n```\nagent receives task ──► classify into scenario ──► aizo recall --scenario \u003cX\u003e\n                                                          │\n                                                          ▼\n                                               inject results into session context\n                                                          │\n                                                          ▼\n                                               generate response with preferences applied\n                                                          │\n                                                          ▼\n                                               aizo apply \u003cused ids\u003e\n```\n\nThis keeps the agent's base context lean while giving it access to the full preference\nprofile. The pattern works like human memory: you don't pre-load every preference into\nworking memory — you recall the relevant ones when the situation calls for it.\n\n**Example flow (coding task):**\n\n```bash\n# Agent classifies the user's request as a coding task, then recalls candidates:\naizo recall --scenario coding --type preference,style,habit,taboo --min-score 3.0 --limit 20 --json\n\n# After generating, mark only the entries that were actually used:\naizo apply 3 8 12\n```\n\n**Example flow (writing task):**\n\n```bash\n# Agent classifies the user's request as a writing task, then:\naizo recall --scenario writing --type preference,style,taboo --limit 15 --json\n```\n\n**Creating scenario-specific entries.** When the user expresses a preference that only\napplies to a certain context, tag it with that scenario so it surfaces only for relevant\ntasks:\n\n```bash\naizo add \"no emojis in code\" \"Rejected emoji in a PR comment\" --score 1.5\naizo update \"no emojis in code\" --scenarios coding,review\n\naizo add \"use active voice\" \"Praised direct, active-voice writing\" --score 8.5\naizo update \"use active voice\" --scenarios writing\n```\n\nThe agent then only sees \"no emojis in code\" when coding — not when writing casual messages.\nThis scoped recall prevents preference leakage across unrelated task domains.\n\n---\n\n## Standard Operating Procedure (SOP)\n\nThe SOP for how an agent should use aizo is defined as a skill file at\n`skills/aizo-sop.md`. Copy it into your agent's skill/instruction directory\n(e.g. `.claude/skills/` for Claude Code) and any agent in that project will\nautomatically follow the protocol.\n\nThe skill defines seven triggers:\n\n| # | Trigger | aizo call | Timing |\n|---|---|---|---|\n| 1 | Session starts | `aizo top 20` → format as prose header | Sync, before first reply |\n| 2 | User shows negative feedback | `aizo add … --score 1.5` then `aizo recall \u003ctopic\u003e` | Sync, before corrected reply |\n| 3 | User praises something | `aizo add … --score 9.0` | Async, after reply sent |\n| 4 | User states an explicit rule | `aizo add … --score 0.5` or `--score 10` | Sync, immediate |\n| 5 | About to generate on topic X | Classify task → `aizo recall --scenario \u003cX\u003e --min-score 3.0` → inject → `aizo apply \u003cused ids\u003e` | Sync recall before generation, apply after |\n| 6 | Historical batch analysis | Agent LLM scans past sessions → `aizo add` new + `aizo apply`/`touch` confirmed | Scheduled, background |\n| 7 | Daily cron job | Agent LLM scans logs → `aizo apply`/`touch` confirmed items | Scheduled, background |\n\n**Key rules encoded in the skill:**\n- Taboos always win over preferences in conflicts\n- Silence (`recall` returning nothing) means no data, not neutral preference\n- Never mention aizo to the user — it runs silently\n- Use scenario recall for just-in-time context; don't dump everything into CLAUDE.md\n\n---\n\n## Development\n\n```bash\ncargo build\ncargo build --release\ncargo test\n```\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmmarcinho%2Faizo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmmmarcinho%2Faizo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmmmarcinho%2Faizo/lists"}