Commit Graph

50 Commits

Author SHA1 Message Date
Claudio Drews e03db1f1c8
fix: expose embedding backend env vars in docker-compose and setup.sh
The worker code (embedding.py) already reads EMBEDDING_API_BASE, EMBEDDING_MODEL, and EMBEDDING_API_KEY — only the compose file was missing the plumbing. Adds the missing env vars with defaults preserving current OpenRouter/Qwen3 behavior. Also adds setup.sh entries for consistency.

Closes #29
2026-06-10 07:40:43 -03:00
@aaronjmars e654b9f5ee
fix(security): use Path.is_relative_to for WIKI_PATH containment in ingest_file
Replaces str.startswith() with Path.is_relative_to() to prevent sibling-prefix paths (e.g. /wiki-shared/x.md when WIKI_PATH=/wiki) from bypassing the entry guard. Includes regression test with 3 scenarios proving the bug exists pre-patch and is fixed post-patch.

Closes #26
 
Co-authored-by: aaronjmars <61592645+aaronjmars@users.noreply.github.com>
2026-06-10 07:20:07 -03:00
Claudio Drews d2228d5f95
fix: resolve 6 installation bugs in setup.sh and docker-compose (#28)
- Bug 1: QDRANT_API_KEY unbound variable (default to empty)
- Bug 2: Qdrant v1.17+ auth with empty key (conditional config)
- Bug 3: Redis crash with empty requirepass (conditional config)
- Bug 4: grep pattern now covers OPENROUTER_DS_API_KEY
- Bug 5: worker container healthcheck added
- Bug 7: execution-agent protocol installed during setup

Co-authored-by: ClaudioDrews <claudio@drews.com.br>
2026-06-08 21:53:15 -03:00
ClaudioDrews 7de2265c66 fix: remove stale knowledge_base_hybrid references, fix generic ENV_PATH
- file_ingestion.py: docstrings now reference 'configured collection'
  instead of hardcoded 'knowledge_base_hybrid' (code already uses
  COLLECTION_NAME env var, defaulting to knowledge_base)
- context_enhancer.py: same docstring fix
- wiki_continuous_ingest.py: ENV_PATH now points to memory-os/docker/.env
  instead of ai-stack/cognitive-agent/.env (production-specific path)
2026-06-07 14:05:31 -03:00
ClaudioDrews 1225af07f0 feat: add anti-theater quality rules to Pre-Action Protocol (Step 2)
Adds explicit examples of bad vs. good Match execution to
prevent performative compliance — the model producing vague
statements like 'Match: relevante' that satisfy the checklist
syntactically but provide zero information.

Also adds a quality rule: Match statements must cite at least
one concrete detail from the injected content so a human can
identify which block was read and what it contains.
2026-06-07 13:42:36 -03:00
ClaudioDrews 66dc9ae503 fix: disable Qdrant API key when empty to prevent auth-on-empty-key bug
Qdrant v1.17+ enables authentication when QDRANT__SERVICE__API_KEY
env var is set (even to empty string). Since the default in setup.sh
is no Qdrant key (localhost-only bind), we now conditionally remove
the line from docker-compose.yml when QDRANT_API_KEY is unset.
2026-06-07 13:33:31 -03:00
ClaudioDrews 59557a86f3 fix: remove leaked docker-compose-monitored.yml, add to gitignore 2026-06-07 13:32:42 -03:00
ClaudioDrews 58027b95e6 feat: add wiki watcher cron to setup.sh (hourly ingestion)
- setup.sh Phase 7b: install cron job for wiki_continuous_ingest.py
- watcher script: fallback to Docker .env for REDIS_PASSWORD in cron context
- Cron runs every hour with idempotent marker check
2026-06-07 13:23:20 -03:00
ClaudioDrews 16e394cd07 fix: align worker UID with host user (1000) for bind mount read access
Worker ran as appuser (UID 10001) but wiki files are owned by
host user hermes (UID 1000) with permissions 600. Changed
Dockerfile to create appuser with UID 1000 so the container
process can read bind-mounted wiki files.
2026-06-07 13:06:11 -03:00
ClaudioDrews 57912f52d1 fix: normalize vault path case and permissions, remove DS-specific key references
- Fix Vault→vault fallback in wiki_continuous_ingest.py, bulk_wiki_ingest.py,
  backfill_decay_metadata.py (bug #1: path mismatch with setup.sh)
- Add chmod 755 on wiki/ and fabric/ after mkdir in Phase 6 (bug #2:
  600 permissions prevent Docker worker read access)
- Simplify API key detection: use OPENROUTER_API_KEY only, remove
  DS-specific fallback in key detection and .env writing
- Keep hooks.py fallback (tries generic first, then DS-specific) —
  correct for backward compatibility
2026-06-07 12:59:04 -03:00
Claudio Drews a25f3a95d6
fix: add context_enhancer symlink step and Mandatory Pre-Action Protocol (#25)
setup.sh:
- Phase 5b: symlink context_enhancer.py to Hermes scripts dir
  (fixes silent ModuleNotFoundError that disabled [qdrant] injection)
- Phase 9: auto-apply execution-agent-protocol.md

modifications/soul-rulebook.md:
- New section: Mandatory Pre-Action Protocol (4-step enforcement)

modifications/execution-agent-protocol.md:
- Standalone protocol for automated application by setup.sh

layers/07-ground-truth.md:
- Document behavioral gap between knowing and executing Ground Truth rules

Co-authored-by: ClaudioDrews <claudio@drews.com.br>
2026-06-07 12:10:06 -03:00
ClaudioDrews 0d6523d6ec chore: add gitignore for live-data test scripts 2026-06-07 10:08:49 -03:00
Claudio Drews 251c16ffad feat: collapse v2 — attenuate Hebbian boost by query-local salience (#24)
- score_all() now multiplies amplify_gain by base salience before
  applying Hebbian cross-source corroboration boost, so globally-
  important structural facts no longer crowd out query-locally-
  relevant facts
- ICARUS_COLLAPSE_AMPLIFY_GAIN env var (default 0.15) tunes the
  tradeoff; raise to 0.20 if genuine corroboration feels undervalued
- All tests passing (_test_collapse.py, collapse_eval.py)
- Real pipeline test: 30-35% token reduction with correct ranking

Closes #23

Co-authored-by: ClaudioDrews <claudio@drews.com.br>
2026-06-07 09:48:00 -03:00
Claudio Drews cd6293f176 Merge pull request #22 from ClaudioDrews/feat/verify-soul-config
feat: add verify_soul_config.py — detect missing Ground Truth in SOUL.md (fixes #19)
2026-06-07 08:26:26 -03:00
ClaudioDrews d696168b89 feat: add verify_soul_config.py — check SOUL.md for Memory OS additions (fixes #19)
Detects whether the four required Memory OS SOUL.md sections are present:
- Ground Truth Hierarchy (layer 7)
- Context Injection Convention
- Fact Feedback Rule
- Honcho Deprecation Notice

Case-insensitive keyword matching. Exits 0 if all pass, 1 otherwise.
Without these sections, injected memory is treated as external sources
to cite rather than prior knowledge — causing the 'internal mechanics leak'
behavior reported in #19.
2026-06-07 08:25:52 -03:00
Claudio Drews afd890e594 Merge pull request #21 from ClaudioDrews/fix/issue-20-yaml-quote-fabric-curate
fix: strip YAML quotes in curate_entry ID comparison (fixes #20)
2026-06-07 08:16:01 -03:00
ClaudioDrews 1abce75a05 fix: strip YAML quotes in curate_entry ID comparison (fixes #20)
m.group(1) captures 'f95842e2' (with quotes) from YAML id: field.
Comparison with unquoted entry_id always failed → no entry ever found.
Added .strip('"') after .strip() to normalize before comparison.
2026-06-07 08:14:40 -03:00
ClaudioDrews 6418ed30a1 v0.2.0 — automated install, community infra, 20+ audit fixes
- setup.sh: one-command install (curl | bash), 10 phases, idempotent
- smoke_test.sh + test_ingestion.py: post-install verification
- .github/: issue templates, PR template, contributing guide
- QUICKSTART.md: quick start with setup.sh as primary method
- README: release notes, install links
- install.md: banner redirecting to automated install
- All docs translated to English
2026-06-05 01:51:24 -03:00
ClaudioDrews 67ceb78202 refactor: extract shared parse_entry into icarus/parsing.py (fixes D01, D09)
D01 — parse_entry YAML fallback was duplicated and buggy (split ': '
breaks on URLs). Primary parser (yaml.safe_load) already handled
URLs correctly; manual fallback is now centralized in one module.

D09 — export-training.py had a duplicate parse_entry with the same
bug. Now imports from parsing.py.

Both files use try/except ImportError to support both package-mode
(icarus plugin) and standalone execution (CLI scripts).

Shared module returns both naming conventions (_body/body, _file/file)
for backward compatibility with fabric-retrieve and export-training.
2026-06-03 17:00:19 -03:00
ClaudioDrews 327b18bf47 Merge PR #13: provider-agnostic LLM extraction (brian-doherty)
Combines HERMES_AGENT_NAME + DeepSeek/custom endpoint vars in
.env.example Strongly Recommended section.
2026-06-03 16:37:38 -03:00
ClaudioDrews 0975b26382 fix: rename docker-compose volume vars to MEMORY_OS_* prefix
B3.1 — CRITICAL: docker-compose.yml inherited host env vars
(WIKI_PATH, HERMES_HOME, FABRIC_DIR), causing dev stacks to
accidentally mount production volumes.

Fix:
- docker-compose.yml: ~/Vault/wiki →
- docker-compose.yml: ~/.hermes →
- docker-compose.yml: ~/Vault/fabric →
- .env.example: document new vars with safety warning
- install.md: add optional volume override section with ⚠️ note

Fallback defaults (./wiki, ./hermes, ./fabric) are preserved —
zero-config dev setup still works out of the box.
2026-06-03 16:24:35 -03:00
ClaudioDrews 545a882157 fix: docker-compose.yml — Qdrant healthcheck usa grep em vez de curl
A imagem qdrant/qdrant:v1.17.1 não inclui curl, wget, python, ps,
pgrep, nc nem /dev/tcp. O healthcheck anterior nunca passava porque
o binário curl não existe.

Corrigido para: sh -c 'grep -q :18BD /proc/net/tcp'
(6333 = 0x18BD)

Bug encontrado durante Nível 2 de testes (stack isolado).
2026-06-03 16:08:24 -03:00
ClaudioDrews 35f85066a4 fix: semantic_dedup.py — adicionar using='dense' ao QueryRequest
Collection knowledge_base usa named vectors (dense + sparse). O Qdrant
exige o parâmetro 'using' em collections com múltiplos vetores nomeados.
Sem ele, query_batch_points retornava 'Not existing vector name error'
em 100% das batches (44/44). O script reportava falsos 0 near-duplicates.

Correção: 1 linha — using='dense' em models.QueryRequest (linha 176).

Validado com --dry-run --threshold 0.95 contra 8886 pontos reais:
0 erros, 1776 near-duplicate pairs detectados.
2026-06-03 15:59:28 -03:00
ClaudioDrews 3fd7cd6faf docs: Fase C — R3 (Ollama), R4 (cron jobs), R5 (agent name), R6 (Qdrant)
R3: .env.example — Embedding backend reestruturado com Option A (Ollama,
recomendado para produção) e Option B (OpenRouter). install.md passo 4
atualizado para mencionar Ollama como opção local.

R4: install.md passo 8 — adicionados 3 cron jobs stack-base na tabela
e nos exemplos CLI: holographic-memory-backup (backup semanal do
memory_store.db), wiki-raw-ingest-monitor (detecção de drift em raw/),
maas-heartbeat (healthcheck Qdrant/Redis/ARQ).

R5: .env.example + install.md passo 6 — adicionado HERMES_AGENT_NAME.
state.py write_entry agora loga warning quando AGENT_NAME não está
definido.

R6: install.md Troubleshooting — nota sobre coexistência de coleções
Qdrant (knowledge_base + outras coleções de agentes externos).
2026-06-03 15:46:31 -03:00
ClaudioDrews 6b11dc554a docs: Fase B — R1 (rulebook amendments) + R2 (soul-rulebook additions)
R1: setup/rulebook.md reescrito como pointer para o novo arquivo
modifications/execution-agent-protocol.md, que formata as 3 seções
(Memory Architecture, Memory OS Docker stack, Mandatory Verifications)
como amendments ao Execution Agent protocol. Cada amendment especifica
onde inserir relativo às regras do protocolo. install.md passo 6
atualizado para refletir o novo formato.

R2: modifications/soul-rulebook.md ganhou duas novas seções:
- Fact feedback rule (fecha o loop de qualidade dos fatos)
- Honcho deprecation (avisa para não configurar Honcho)
2026-06-03 15:32:34 -03:00
ClaudioDrews 170a6ba6be fix: Fase A — 3 correções de código (R7, R8, R9)
R7 (V5.03/B11): hooks.py _search_qdrant — os.environ mutation agora usa
try/finally com restore. Chave OPENROUTER_API_KEY é injetada
temporariamente só durante o import do context_enhancer.

R8 (V5.06/B06): state.py write_entry e write_memory_file — substituído
path.write_text() por tmp + rename (escrita atômica). Evita corrupção
de arquivo em caso de crash durante o write.

R9 (item 5): state.py read_pending — normalizado agent = AGENT_NAME or
'agent' para consistência com write_entry. Corrige lógica de assignment
quando HERMES_AGENT_NAME não está definido.
2026-06-03 15:05:54 -03:00
Brian Doherty 2d6281e86c feat: provider-agnostic LLM extraction
Make the Icarus extraction pipeline work with any LLM provider
instead of hardcoding OpenRouter.

New env vars (all optional, backward compatible):
  DEEPSEEK_API_KEY       — route directly to api.deepseek.com
  ICARUS_ENDPOINT        — fully custom v1/chat/completions URL
  ICARUS_API_KEY_ENV     — env var name for the custom endpoint key

Resolution priority:
  1. ICARUS_ENDPOINT + ICARUS_API_KEY_ENV (fully custom)
  2. DEEPSEEK_API_KEY → api.deepseek.com
  3. OPENROUTER_API_KEY → openrouter.ai (existing behaviour, unchanged)

Model names are automatically normalized: OpenRouter-style
deepseek/deepseek-v4-flash slugs have the provider prefix
stripped for direct API calls.

No breaking changes. If DEEPSEEK_API_KEY and ICARUS_ENDPOINT
are both unset, behaviour is identical to previous versions.
2026-06-03 11:29:15 -05:00
ClaudioDrews 144795bf74 perf: Qdrant query_batch_points + SQLite FTS5 for semantic_dedup and fabric-retrieve
V4.01: Replace O(n²) brute-force cosine similarity in semantic_dedup.py
  with Qdrant query_batch_points() — delegates nearest-neighbor search
  to the native HNSW index. Batch size auto-scales (min 200, adjusted
  for collection size). Self-match excluded server-side via
  HasIdCondition filter. Graceful fallback if qdrant-client not installed.

V4.03: Replace glob+parse in fabric-retrieve.py retrieve() with SQLite
  fabric_index + fabric_fts (FTS5). _ensure_fabric_index() rebuilds the
  index lazily when any fabric .md mtime exceeds the stored max mtime.
  Transactional rebuild (BEGIN; DELETE; DELETE; ...; COMMIT) prevents
  index corruption on partial failure. All score_entry fields preserved
  as columns — no YAML parsing after initial index build.
2026-06-03 12:14:30 -03:00
ClaudioDrews 45e2b075f7 perf: O(1) lookups for obsidian _find_entry_file + export-training _resolve_ref
V4.02: Replace glob+parse scan in _find_entry_file with in-memory dict index
  - _build_entry_index() scans fabric dirs once, builds (agent,id)→stem dict
  - Index rebuilds lazily when fabric_dir.stat().st_mtime changes
  - O(n) rebuild only on changes, O(1) per lookup thereafter

V4.07: Replace 4× O(n) linear scans in _resolve_ref with prebuilt indices
  - index_by_id, index_by_cycle: exact dict lookups (covers ~90% of calls)
  - by_agent_entries: scoped substring scans (per-agent, not full list)
  - Slow path preserved for standalone calls without indices
  - All 4 call sites in build_pairs() updated to pass indices
2026-06-03 12:04:14 -03:00
ClaudioDrews 1422a6d583 fix: resolve 5 easy Phase 4 performance/resilience issues
V4.04: Add retry_transient() to dlq_manager — re-enables reported transient
  failures for retry with --retry CLI flag, increments retry_count/last_retry

V4.05: save_report() now truncates JSONL to MAX_REPORT_HISTORY entries
  after each append (best-effort rotation)

V4.06: Wrap datetime.fromisoformat() in try/except (ValueError, TypeError)
  in get_status_summary() — skips entries with malformed timestamps

V4.08: Replace body[:50] dedup key with hashlib.sha256(body).hexdigest()
  in fabric-retrieve.py deduplicate()

V4.09: Add OrderedDict LRU cache (256 entries) to embedding.py get_embedding()
  — avoids recomputing embeddings for repeated text
2026-06-03 11:53:18 -03:00
ClaudioDrews e5edb58a19 fix: resolve all 8 Phase 3 config/path issues
V3.01-V3.03: Replace hardcoded Path.home() / 'Vault' with os.environ.get()
  - wiki_continuous_ingest.py: WIKI_ROOT via env with fallback
  - bulk_wiki_ingest.py: WIKI_ROOT + EMBEDDING_MODEL via env with fallback
  - backfill_decay_metadata.py: VAULT_ROOT via VAULT_PATH env with fallback

V3.04-V3.05: Replace hardcoded EMBEDDING_MODEL string with os.environ.get()
  - context_enhancer.py + bulk_wiki_ingest.py

V3.06: Replace ~/.hermes til fallback with ./hermes (Docker doesn't expand ~)

V3.07: Add /fabric volume mount (~/Vault/fabric:/fabric:rw)

V3.08: Add Qdrant healthcheck + change worker qdrant dependency from
  service_started to service_healthy
2026-06-03 11:44:22 -03:00
ClaudioDrews 384395b78d fix: resolve all 7 Phase 1 setup/infra issues
V1.01: Add fastembed, httpx, redis to requirements.txt (now 10 lines, 9 deps)
V1.03: Create setup/setup_db.py — idempotent SQLite schema for state.db + memory_store.db
V1.04: Create .dockerignore (21 patterns — .env, *.key, __pycache__, etc.)
V1.05: Dockerfile COPY --chown=appuser:appuser (after useradd, before USER switch)
V1.06: Add EXPOSE 8000 + HEALTHCHECK (Redis ping, 30s interval)
V1.07: Document database setup as Step 2 in install.md (pip install + setup_db.py + table listing)
V1.08: Remove change-me from REDIS_PASSWORD in .env.example
V1.09: Replace gcc with build-essential + python3-dev in Dockerfile
2026-06-03 11:31:04 -03:00
ClaudioDrews 55ba9cee1c fix: move get_sparse_vector outside get_embedding body (V2.12 regression)
get_sparse_vector was accidentally inserted between get_embedding's
signature and its body, disconnecting the embedding call and leaving
module-level code referencing undefined variables. Moved to standalone
function before get_embedding.
2026-06-03 11:03:18 -03:00
ClaudioDrews a3d644a5c9 fix: resolve 4 code-critical issues from Fase 2 audit
V2.07 (A01): Replace subprocess.run(['arq', ...]) with programmatic
  arq.worker.run_worker(WorkerSettings). Fixes signal handling,
  graceful shutdown, and logging unification.

V2.10 (D11): Fix filename → file_path in backfill_decay_metadata.py
  resolve_timestamp() now reads payload.file_path (consistent with
  what bulk_wiki_ingest.py writes). Replaced VAULT_ROOT path
  reconstruction with direct Path(file_path).

V2.11 (D05): Auto-create Qdrant collection in bulk_wiki_ingest.py
  If collection doesn't exist, creates it with hybrid schema
  (dense 4096d Cosine + sparse BM25) instead of sys.exit(1).

V2.12 (D27): Add sparse vector generation to bulk_wiki_ingest.py
  Optional fastembed BM25 sparse vectors alongside dense embeddings.
  Falls back to dense-only if fastembed not installed. Vectors stored
  as Qdrant named vectors: {'dense': ..., 'sparse': ...}
2026-06-03 10:54:53 -03:00
ClaudioDrews ff781f9824 feat: add EMBEDDING_API_KEY for authenticated non-OpenRouter endpoints (fixes #8)
embedding.py:
- Add EMBEDDING_API_KEY env var (no fallback — explicit per-branch)
- OpenRouter branch: uses OPENROUTER_API_KEY + vendor headers
- Generic branch: sends Authorization: Bearer <EMBEDDING_API_KEY> if set
- Unauth fallback: no header (localhost, no auth needed)
- Credential isolation: no cross-branch key leakage

.env.example + setup/install.md:
- Document EMBEDDING_API_KEY as optional for non-OpenRouter
  authenticated endpoints (vLLM --api-key, custom hosted services)
2026-06-03 09:37:38 -03:00
ClaudioDrews 4e1f543a1d docs: rewrite installation guide with real scripts and idempotent modifications (fixes #11)
Replace incomplete/outdated install instructions with accurate,
detailed steps grounded in production infrastructure.

setup/install.md:
- Step 3: run docker compose in-place (not via cp to ~/memory-os/)
- Step 5: explicit ~/.hermes/rulebook.md path, create-if-missing,
  idempotency guard with Memory OS Additions v1 marker
- Step 6: document VAULT_PATH, wiki directory structure,
  link to vault-curator as optional enrichment tool
- Step 7: replace fictional crontab with real maintenance scripts
  and hermes cron create commands; add backfill prerequisite note
  and exempt-prefix env var docs

setup/rulebook.md (NEW):
- Generic template with 3 blocks: Memory Architecture,
  Memory OS infrastructure, Mandatory Verifications
- Idempotency markers on every block

modifications/soul-rulebook.md:
- SOUL.md-only (rulebook sections moved to setup/rulebook.md)
- Conditional instructions (add level 2 vs full hierarchy)
- Conflict resolution table (4 rules)
- Context injection convention with acting vs reasoning distinction

scripts/:
- 8 maintenance scripts updated with sanitized equivalents
- decay_scanner.py, semantic_dedup.py: collection_ → DECAY/DEDUP_EXEMPT_PREFIXES env vars
- reflection_trigger.py: hardcoded venv path → /usr/bin/env python3
- All shebangs normalized, all internal references removed
2026-06-03 09:29:19 -03:00
ClaudioDrews b33b8d4196 fix: SyntaxError on QDRANT_API_KEY placeholder (fixes #10)
Split the corrupted line 15 into two valid assignments:
- QDRANT_API_KEY = os.environ.get('QDRANT_API_KEY', '')
- EMBEDDING_DIMS = int(os.environ.get('EMBEDDING_DIMS', '4096'))

The merged line 'QDRANT_API_KEY=os.env...DIMS = ...' was a leftover
placeholder that prevented the ARQ worker from starting.

Reported-by: CG1up
2026-06-03 08:18:32 -03:00
ClaudioDrews 598eaf19d0 fix(sanitize): change system prefix replacement from silent removal to [REDACTED]
- Silent removal (empty string) left grammatically broken sentences
  and no audit trail. [REDACTED] preserves context structure.
- Control chars and zero-width Unicode keep empty string replacement
  (invisible characters, removal is correct).
- Updated 4 test assertions in _test_sanitize.py.
2026-06-02 13:45:02 -03:00
David Soff a5c1344afb
security(hooks, context_enhancer): add dual-layer prompt injection sanitization (#5)
security(hooks, context_enhancer): add dual-layer prompt injection sanitization

- Layer 1 (hooks.py): aggressive sanitization at prompt boundary with
  11 regex patterns + heuristic. Detects override directives, template
  injection, URI schemes, system prefixes, HTML/XML, control chars,
  zero-width Unicode, and code fences. Applied to fabric, Qdrant,
  sessions, and facts injection points. Complements existing
  _is_system_injection() (which filters ingest, not egest).

- Layer 2 (context_enhancer.py): lightweight sanitization on all
  search result content_preview outputs (hybrid, dense, sparse,
  lexical, sqlite).

- _test_sanitize.py: manual validation script with 24 test cases.

- Replacement strategy: [REDACTED] preserves audit trail and
  grammatical context instead of silent removal.
2026-06-02 13:43:34 -03:00
David Soff 0d6fc33c00
fix(context_enhancer): refactor embed_query_sparse to use stdin (#4)
fix(context_enhancer): refactor embed_query_sparse to use stdin instead of f-string interpolation

- Eliminates shlex.quote() crash with apostrophes (SyntaxError in subprocess)
- Eliminates user text interpolation into Python code string
- Hardcodes BM25 model name (was already hardcoded module-level)
- Corrects FastEmbed API usage: model.embed([query]) instead of model.embed(string)
2026-06-02 13:28:32 -03:00
brian-doherty 02018160d2
fix(worker): add missing import os, Qdrant auth, and env config (#6)
Fix 4 bugs that prevent the ARQ worker from booting with a
Qdrant instance that has an API key set:

1. reflection.py: add missing 'import os' (NameError crash at
   COLLECTION_NAME = os.environ.get(...))

2. local_qdrant.py: read QDRANT_API_KEY from environment

3. local_qdrant.py: pass api_key= to AsyncQdrantClient and set
   https=False to prevent SSL error when API key triggers
   auto-HTTPS against a local HTTP Qdrant instance

4. docker-compose.yml: pass QDRANT_API_KEY env var to the
   worker service so the key is available inside the container
2026-06-02 13:21:30 -03:00
Claudio Drews 8e8ea95458
fix(embedding): make OpenRouter auth and headers conditional — unblock 100% local usage (#7)
- Remove unconditional OPENROUTER_API_KEY check that blocked local providers
  (Ollama, vLLM, llama.cpp) from running without an API key
- Send OpenRouter-specific headers (HTTP-Referer, X-Title) only when
  EMBEDDING_API_BASE contains 'openrouter'
- Stop sending empty Authorization header to non-OpenRouter endpoints
- Update .env.example and setup/install.md to clarify that
  OPENROUTER_API_KEY is only required for OpenRouter

Closes #1

Co-authored-by: ClaudioDrews <claudio@drews.com.br>
2026-06-02 13:05:12 -03:00
Claudio Drews bae035f8fb
Merge pull request #3 from ClaudioDrews/fix/embedding-provider-agnostic
fix: make embedding provider-agnostic via env vars (closes #1)
2026-06-02 10:11:58 -03:00
Claudio Drews d206c3eae2
Merge pull request #2 from ClaudioDrews/fix/6-to-7-layers
docs: fix "Six" → "Seven" memory layers in README
2026-06-02 10:11:54 -03:00
Claudio Drews 1281d7a778 fix: make embedding provider-agnostic via env vars
- embedding.py: EMBEDDING_API_BASE and EMBEDDING_MODEL now read from env
  with OpenRouter defaults (preserves backward compatibility)
- .env.example: document embedding backend config with Qwen3 rationale
- setup/install.md: update prerequisite to reflect configurable backend
- layers/05-qdrant.md: add "Why Qwen3-Embedding-8B" section
  (multilingual, quality, speed, cost)

Closes #1
2026-06-02 09:45:31 -03:00
Claudio Drews 7c9a8f02ae docs: fix "Six" → "Seven" memory layers in README 2026-06-02 09:42:58 -03:00
Claudio Drews a4ca094a7b docs: add ground-truth hierarchy layer (07) — the critical missing piece
Context injection delivers memory into the prompt, but without an explicit
Ground Truth hierarchy the agent treats it as optional suggestion. This
layer documents the fix: injected memory ([qdrant], [fabric], [sessions],
[facts]) ranked as authoritative for documented knowledge, with clear
conflict-resolution rules against terminal output and training knowledge.
2026-06-01 19:23:55 -03:00
ClaudioDrews b7d637a52c Add pixel-art banner to README 2026-05-31 23:32:27 -03:00
ClaudioDrews 636acabac7 Add 3 operational skills: memory-architecture, context-injection, llm-wiki 2026-05-31 16:59:12 -03:00
ClaudioDrews 0b32ffcfc2 Initial commit: Memory OS — 6-layer memory architecture for Hermes Agent 2026-05-31 16:50:37 -03:00