diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..54b4853 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,81 @@ +# Didactyl — Agent Instructions + +## Build + +**Always use `./build_static.sh` to build the binary.** Never run `make` directly — the default `all` target prints a warning and exits with an error. `make` is kept only for auxiliary targets (`make clean`, `make deps`, `make test_pool`). + +```bash +./build_static.sh # Release build (static MUSL via Docker) +./build_static.sh --debug # Debug build +./build_static.sh --platform=linux/arm64 # Cross-compile +``` + +## Project Overview + +Didactyl is a Nostr agent written in C (C99). It runs as a long-lived daemon that listens for DMs from its admin, processes them via an LLM, and can execute tools (post notes, query relays, manage skills, etc.). + +## Key Files + +| File | Purpose | +|------|---------| +| `src/main.c` | Entry point, CLI arg parsing, signer construction | +| `src/setup_wizard.c` | Interactive setup wizard (8 steps) | +| `src/config.c` / `src/config.h` | Config loading from genesis.jsonc | +| `src/nostr_handler.c` / `src/nostr_handler.h` | Nostr relay pool, event publish/subscribe | +| `src/llm.c` / `src/llm.h` | LLM HTTP client (OpenAI-compatible API) | +| `src/agent.c` | Agent loop: DM → LLM → tool dispatch → response | +| `src/tools/` | Tool implementations (one file per tool) | +| `src/tools/tools_schema.c` | Tool schemas (JSON Schema for each tool) | +| `src/tools/tools_dispatch.c` | Tool dispatch routing | +| `src/default_events.h` | Default relays, skill templates | +| `src/signer_health.c` / `src/signer_health.h` | Signer health monitoring | +| `nostr_core_lib/` | Vendored nostr_core_lib (v0.6.15) | +| `genesis.jsonc.example` | Example genesis config | +| `build_static.sh` | Static build script (Docker + Alpine + musl) | +| `Dockerfile.alpine-musl` | Dockerfile for static builds | +| `increment_and_push.sh` | Version bump + git tag + push | + +## Coding Conventions + +- **Language**: C99 (`-std=c99`) +- **Style**: 4-space indentation, K&R braces +- **Naming**: `snake_case` for functions and variables, `UPPER_CASE` for macros +- **Headers**: Include guard via `#ifndef` / `#define` / `#endif` +- **Error handling**: Return negative error codes, use `NOSTR_SUCCESS` (0) from `nostr_core_lib/nostr_core/nostr_common.h` +- **Logging**: Use `DEBUG_INFO()`, `DEBUG_WARN()`, `DEBUG_ERROR()` macros from `src/debug.h` +- **Memory**: Manual malloc/free; no GC +- **JSON**: Use cJSON library (`nostr_core_lib/cjson/`) + +## Key Architecture Decisions + +- **Signer abstraction**: All crypto operations go through `nostr_signer_t` (local or remote via n_signer). The signer is constructed in `main.c` and passed through the tool context. +- **Role paths**: Uses BIP-44 derivation paths (`role_path`) instead of the old `nostr_index` selectors. See `docs/SIGNER.md`. +- **Wizard**: The setup wizard (`src/setup_wizard.c`) is a plain-text interactive TUI (no ncurses). It uses `fprintf(stderr, ...)` for output and `fgets()` for input. +- **Config persistence**: Config is published as NIP-44 encrypted kind 30078 events on Nostr, keyed by `d_tag` (e.g. `"user-settings"`). +- **Skills**: Agent skills are kind 31124 events with `d_tag` identifiers. They contain markdown with template variables like `{{my_kind0_profile}}`, `{{my_npub}}`, `{{nostr_dm_history(...)}}`. + +## Testing + +```bash +cd tests && python3 run_tests.py # Run test suite +``` + +Tests are in `tests/suites/` using a Python harness. Each test spawns a didactyl instance with a test genesis config and checks behavior via the HTTP admin API. + +## Versioning + +Versions follow `vMAJOR.MINOR.PATCH` format. Use `./increment_and_push.sh "description"` to bump the patch version, commit, tag, and push. + +## Nostr Core Library + +The vendored `nostr_core_lib/` is a static library (`libnostr_core_x64.a`). To rebuild it: + +```bash +cd nostr_core_lib && ./build.sh --nips=001,004,005,006,011,013,017,019,021,042,044,046,059,060,061 +``` + +## Important Notes + +- The wizard runs before `main()` sets up the CA bundle, so `fetch_models_for_llm_config()` in the wizard explicitly calls `nostr_http_set_ca_bundle()`. +- ppq.ai does not expose a balance/credits endpoint — the wizard skips balance checks for `"ppq"` provider. +- The `relay_remove_index()` function in `setup_wizard.c` is unused (relays use toggle-based enable/disable, not removal). diff --git a/README.md b/README.md index 0a78f97..ab81b85 100644 --- a/README.md +++ b/README.md @@ -54,11 +54,11 @@ Skills compose by adoption-list order (`10123`) and trigger tags carry runtime e Didactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers. -## Current Status — v0.2.69 +## Current Status — v0.2.70 **Active build — this project is barely working. Experiment at your own risk.** -> Last release update: v0.2.69 — Makefile: replace default 'all' target with warning to use build_static.sh instead +> Last release update: v0.2.70 — Add AGENTS.md with build instructions, project overview, coding conventions, and key architecture decisions - Connects to configured relays with auto-reconnect and relay state transition logging - Publishes configured startup events per relay as each relay becomes connected diff --git a/src/main.h b/src/main.h index 4778908..738d9e2 100644 --- a/src/main.h +++ b/src/main.h @@ -12,8 +12,8 @@ // Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros #define DIDACTYL_VERSION_MAJOR 0 #define DIDACTYL_VERSION_MINOR 2 -#define DIDACTYL_VERSION_PATCH 69 -#define DIDACTYL_VERSION "v0.2.69" +#define DIDACTYL_VERSION_PATCH 70 +#define DIDACTYL_VERSION "v0.2.70" // Agent metadata #define DIDACTYL_NAME "Didactyl"