Skip to content

Latest commit

 

History

History
126 lines (104 loc) · 6.71 KB

AGENTS.md

File metadata and controls

126 lines (104 loc) · 6.71 KB

AGENTS.md — hivemind-sqlite-database

Guidance for AI coding agents (and humans) working in this repository. Read it fully before making changes.

SQLite (and optional SQLCipher-encrypted) AbstractDB backend plugin for hivemind-core, storing HiveMind client records (API keys, crypto keys, ACLs). Part of the HiveMind ecosystem — a protocol for connecting satellite devices to a hub running OpenVoiceOS. The hub is HiveMind-core; the plugin contract (AbstractDB) and loader live in hivemind-plugin-manager.

Setup

pip install -e .
# encrypted-database support (SQLCipher / AES-256):
pip install -e ".[cipher]"   # needs libsqlcipher system lib (apt install libsqlcipher-dev)

Test

pytest tests/

Single suite lives in tests/test_sqlitedb.py. The repo's own tests.yml runs it with -p no:ovoscope and exercises both the plain and the SQLCipher path. Cipher tests need libsqlcipher-dev installed.

Lint/Typecheck

Ruff, via the shared lint.yml workflow (ruff: true, no pre-commit config present). No typecheck configured.

Layout

  • hivemind_sqlite_database/__init__.py — the entire plugin: SQLiteDB dataclass extending AbstractDB. Schema creation, PRAGMA user_version migration (v1→v2 folds legacy intent_blacklist/skill_blacklist columns into Client.metadata), and CRUD (add_item, search_by_value, get_client_by_id, __iter__, __len__, commit).
  • hivemind_sqlite_database/version.py — version constants (do not edit).
  • tests/test_sqlitedb.py — full behavioural suite.

Entry-point group: hivemind.database → hivemind-sqlite-db-plugin = hivemind_sqlite_database:SQLiteDB. Discovered by hivemind-plugin-manager; selected in hivemind-core config under database.module.

Conventions

  • Branches: dev (work) and master (stable). NEVER main.
  • Never edit version.py; gh-automations bumps semver from conventional-commit prefixes (feat:/fix:/feat!:).
  • New repos private by default.
  • Commit identity: JarbasAi jarbasai@mailfence.com.
  • Reference OpenVoiceOS/gh-automations reusable workflows at @dev.
  • No Neon / neon-* references.
  • No meta-commentary (no history, no dates) in code, docs, commits, or PRs — describe current state only.
  • CI is provided by OpenVoiceOS/gh-automations.

Working agreement (org-wide law)

  • Never push dev or master. Work on a feature branch and open a draft PR into dev. A human merges. You do not merge your own PRs.
  • Never merge or modify Release X → master PRs. They are the maintainer's stable-release mechanism, generated by automation.
  • One commit per PR (squash before pushing). Conventional commits; feat: only for a user-visible new capability. fix:, docs:, chore:, ci: otherwise.
  • Disclose AI authorship. Every PR/issue/comment an agent writes carries, at the top: > 🤖 Auto-generated by <model> via Claude Code — NOT human-reviewed. Verify before acting. PR bodies are plain human prose (3–6 short paragraphs), no tables or section-symbol spray.
  • Never edit someone else's issue, PR description, or comment. Add a comment instead; on your own PRs, edit the body rather than piling on comments.
  • No scratch files, committed virtualenvs, __pycache__, .pyc, .egg-info, or build artifacts in a PR. git show --stat shows only intended files.

Dependencies

  • Floor pins only (>=X.Y.Za1), bumped when a feature or fix is actually needed. No upper caps unless a specific released version is genuinely broken. pyproject.toml currently pins hivemind-plugin-manager>=0.5.0,<1.0.0 — that upper cap is a deviation from the floor-pins-only rule; treat removing it (once confirmed safe against 1.x) as a standing cleanup, not something to add to.
  • No lockfiles, ever. Target the latest alphas (--prerelease=allow).
  • Everything in pyproject.toml (deps, metadata, version). Never install from git — depend on a published PyPI alpha.
  • Apache-2.0. Do not add GPL/AGPL dependencies.

Tests

  • Adversarial by default. A regression test must fail before the fix and pass after — prove it by reverting only the source (git apply -R, never git stash across worktrees) and watching the test flip.
  • Tests must be mutation-proof: gutting the feature must fail the test. A test that only asserts a mock was called, without asserting the real behaviour, is weak — note it.
  • Never skip a test because an optional dependency is missing (cipher tests need libsqlcipher-dev; install it, do not skip).
  • CI green is permission to review, not to merge. A non-trivial change gets an adversarial review before it lands.

Repo-specific rules

  • This is the AUTH hot path for hivemind-core admission: get_client_by_id (used by refresh()) and the rest of the CRUD surface must fail SAFE. Every query is wrapped in try/except (sqlite3.Error, TypeError, ValueError), logs, and returns None/False/0 on error — never raises past the plugin boundary, never fabricates a permissive client record. Preserve this on any change; a bug here means a bad key silently gets treated as absent rather than admitted, which is the safe direction — never invert it.
  • ACL fields (can_broadcast, can_escalate, can_propagate, and the blacklists folded into metadata) must round-trip exactly through add_item → _row_to_client. Any schema or serialization change needs a test that writes a Client with non-default ACL values and reads it back.
  • _VALID_COLUMNS allowlist gates search_by_value keys; SQL column name is interpolated only after passing that frozenset (issue #1 tracks an SQL-security review — do not relax this allowlist without closing that concern).
  • Legacy intent_blacklist/skill_blacklist/message_blacklist columns remain in the table but are NULLed on write; canonical data lives in the metadata JSON column. message_blacklist is purged entirely (not part of Client). Do not resurrect writes to the legacy columns.
  • migrate() guards on getattr(AbstractDB, "SCHEMA_VERSION", 1) so it tolerates older hivemind-plugin-manager that predates the constant — do not assume the attribute exists.
  • WAL journal mode is enabled for both plain and encrypted DBs; check_same_thread=False with a threading.Lock guarding writes. Any new write path must take that lock.
  • Encrypted and plaintext databases are not interchangeable and there is no migration between them; lost passphrase = unrecoverable data.
  • tests.yml is a repo-local workflow separate from the shared build-tests; both run the same suite.