diff --git a/README.md b/README.md index 428b9ad..8127b5e 100644 --- a/README.md +++ b/README.md @@ -78,18 +78,14 @@ All settings are via environment variables: ## Markdown Config Files -Place these in your `CONFIG_DIR` (default: `./config/`). The gateway reads them fresh on every event — edit them anytime, no restart needed. +Place these in your `CONFIG_DIR` (default: `./config/`). The gateway reads them fresh on every event — edit them anytime, no restart needed (except `agents.md` and `heartbeat.md` which are parsed at startup for cron/heartbeat timers). | File | Purpose | Required | |------|---------|----------| -| `identity.md` | Agent name, role, specialization | Yes | -| `soul.md` | Personality, tone, values, behavior defaults | Yes | -| `agents.md` | Operating rules, safety boundaries, cron jobs, hooks | No | -| `user.md` | Info about you: name, preferences, context | No | +| `CLAUDE.md` | Persona: identity, personality, user context, tools — all in one | Yes | +| `agents.md` | Operating rules, cron jobs, hooks (parsed by gateway) | No | | `memory.md` | Long-term memory (agent can write to this) | No (auto-created) | -| `tools.md` | Tool configs, API notes, usage limits | No | -| `heartbeat.md` | Proactive check definitions | No | -| `boot.md` | Bootstrap configuration | No | +| `heartbeat.md` | Proactive check definitions (parsed by gateway) | No | Missing optional files are created with default headers on first run. diff --git a/docs/FUTURE-FEATURES.md b/docs/FUTURE-FEATURES.md index 0925281..a068cd9 100644 --- a/docs/FUTURE-FEATURES.md +++ b/docs/FUTURE-FEATURES.md @@ -148,3 +148,24 @@ Our approach: Since we use `--dangerously-skip-permissions`, the agent can run B 5. Agent-managed tasks (dynamic scheduling) 6. Conversation archiving (audit trail) 7. Everything else as needed + +--- + +## Completed: Config Simplification + +Merged `soul.md`, `identity.md`, `user.md`, and `tools.md` into a single `CLAUDE.md` file. The config directory is now: + +``` +config/ +├── CLAUDE.md ← Persona: identity, personality, user context, tools (all in one) +├── agents.md ← Cron jobs + Hooks (parsed by gateway at startup) +├── heartbeat.md ← Heartbeat checks (parsed by gateway at startup) +├── memory.md ← Long-term memory (agent-writable, auto-created) +└── sessions.json ← Channel → session ID map (auto-generated) +``` + +Why this split: +- `CLAUDE.md` is pure prompt context — the agent reads it but the gateway doesn't parse it +- `agents.md` and `heartbeat.md` are parsed programmatically by the gateway to set up cron timers and heartbeat intervals +- `memory.md` is the only file the agent writes to — keeping it separate prevents the agent from accidentally overwriting persona config +- Fewer files to manage, one place to edit your persona diff --git a/docs/PROCESS-FLOW.md b/docs/PROCESS-FLOW.md index d4d7575..03874e2 100644 --- a/docs/PROCESS-FLOW.md +++ b/docs/PROCESS-FLOW.md @@ -119,12 +119,11 @@ When the event reaches the front of the queue, the Agent Runtime reads ALL markd ``` config/ -├── identity.md → Agent name, role, vibe -├── soul.md → Personality, tone, values -├── agents.md → Operating rules, safety boundaries -├── user.md → Info about the human -├── memory.md → Long-term memory (agent can write to this) -└── tools.md → Tool configs, API notes +├── CLAUDE.md → Persona: identity, personality, user context, tools +├── agents.md → Operating rules, cron jobs, hooks +├── memory.md → Long-term memory (agent-writable) +├── heartbeat.md → Proactive check definitions +└── sessions.json → Channel → session ID map (auto-generated) ``` Files are read fresh every time — edit them while the gateway is running and the next event picks up changes. diff --git a/package-lock.json b/package-lock.json index 4c832f9..fe3d378 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,9 @@ "dependencies": { "discord.js": "^14.25.1", "dotenv": "^17.3.1", - "node-cron": "^4.2.1" + "node-cron": "^4.2.1", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3" }, "devDependencies": { "@types/node": "^25.3.0", @@ -601,6 +603,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.58.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.58.0.tgz", @@ -1172,6 +1180,15 @@ "node": ">=12" } }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/chai": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", @@ -1182,6 +1199,21 @@ "node": ">=18" } }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "license": "MIT" + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/discord-api-types": { "version": "0.38.40", "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.38.40.tgz", @@ -1230,6 +1262,15 @@ "url": "https://dotenvx.com" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/es-module-lexer": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", @@ -1322,12 +1363,24 @@ "node": ">=12.17.0" } }, + "node_modules/fast-copy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz", + "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -1374,6 +1427,21 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "license": "MIT" + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/lodash": { "version": "4.17.23", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", @@ -1402,6 +1470,15 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -1441,6 +1518,24 @@ ], "license": "MIT" }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -1468,6 +1563,67 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^4.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -1497,6 +1653,32 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/pure-rand": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", @@ -1514,6 +1696,21 @@ ], "license": "MIT" }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -1569,6 +1766,31 @@ "fsevents": "~2.3.2" } }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/siginfo": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", @@ -1576,6 +1798,15 @@ "dev": true, "license": "ISC" }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1586,6 +1817,15 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/stackback": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", @@ -1600,6 +1840,30 @@ "dev": true, "license": "MIT" }, + "node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -1875,6 +2139,12 @@ "node": ">=8" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, "node_modules/ws": { "version": "8.19.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", diff --git a/package.json b/package.json index cb4cc11..6fd3b76 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "dependencies": { "discord.js": "^14.25.1", "dotenv": "^17.3.1", - "node-cron": "^4.2.1" + "node-cron": "^4.2.1", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3" }, "devDependencies": { "@types/node": "^25.3.0", diff --git a/src/bootstrap-manager.ts b/src/bootstrap-manager.ts index 1564fd6..2c57635 100644 --- a/src/bootstrap-manager.ts +++ b/src/bootstrap-manager.ts @@ -14,15 +14,13 @@ export interface BootstrapResult { const DEFAULT_OPTIONAL_DEFAULTS: Record = { "agents.md": "# Operating Rules\n", - "user.md": "# User Context\n", "memory.md": "# Memory\n", - "tools.md": "# Tool Configuration\n", "heartbeat.md": "# Heartbeat\n", }; const BUILTIN_BOOT_CONFIG: BootConfig = { - requiredFiles: ["soul.md", "identity.md"], - optionalFiles: ["agents.md", "user.md", "memory.md", "tools.md", "heartbeat.md"], + requiredFiles: ["CLAUDE.md"], + optionalFiles: ["agents.md", "memory.md", "heartbeat.md"], defaults: { ...DEFAULT_OPTIONAL_DEFAULTS }, }; diff --git a/src/markdown-config-loader.ts b/src/markdown-config-loader.ts index d7a2a34..9a83da1 100644 --- a/src/markdown-config-loader.ts +++ b/src/markdown-config-loader.ts @@ -2,55 +2,37 @@ import { readFile, writeFile } from "node:fs/promises"; import { join } from "node:path"; export interface MarkdownConfigs { - soul: string | null; - identity: string | null; + /** CLAUDE.md — persona: identity, soul, user context, tools (all in one) */ + persona: string | null; + /** agents.md — operating rules, cron jobs, hooks (parsed by gateway) */ agents: string | null; - user: string | null; + /** memory.md — long-term memory (agent-writable) */ memory: string | null; - tools: string | null; } -const CONFIG_FILES = ["soul.md", "identity.md", "agents.md", "user.md", "memory.md", "tools.md"] as const; - -type ConfigKey = "soul" | "identity" | "agents" | "user" | "memory" | "tools"; - -const FILE_TO_KEY: Record = { - "soul.md": "soul", - "identity.md": "identity", - "agents.md": "agents", - "user.md": "user", - "memory.md": "memory", - "tools.md": "tools", -}; - export class MarkdownConfigLoader { async loadAll(configDir: string): Promise { const configs: MarkdownConfigs = { - soul: null, - identity: null, + persona: null, agents: null, - user: null, memory: null, - tools: null, }; - for (const filename of CONFIG_FILES) { - const key = FILE_TO_KEY[filename]; - const filePath = join(configDir, filename); + // CLAUDE.md — main persona file + configs.persona = await this.loadFile(configDir, "CLAUDE.md"); + if (!configs.persona) { + console.warn("Warning: CLAUDE.md not found in " + configDir); + } - try { - const content = await readFile(filePath, "utf-8"); - configs[key] = content; - } catch { - if (filename === "memory.md") { - const defaultContent = "# Memory\n"; - await writeFile(filePath, defaultContent, "utf-8"); - configs[key] = defaultContent; - } else { - console.warn(`Warning: ${filename} not found in ${configDir}`); - configs[key] = null; - } - } + // agents.md — parsed by gateway for cron/hooks, also included in prompt + configs.agents = await this.loadFile(configDir, "agents.md"); + + // memory.md — agent-writable long-term memory + configs.memory = await this.loadFile(configDir, "memory.md"); + if (!configs.memory) { + const defaultContent = "# Memory\n"; + await writeFile(join(configDir, "memory.md"), defaultContent, "utf-8"); + configs.memory = defaultContent; } return configs; diff --git a/src/system-prompt-assembler.ts b/src/system-prompt-assembler.ts index 123dd55..0f3c43a 100644 --- a/src/system-prompt-assembler.ts +++ b/src/system-prompt-assembler.ts @@ -3,29 +3,20 @@ import type { MarkdownConfigs } from "./markdown-config-loader.js"; const PREAMBLE = "You may update your long-term memory by writing to memory.md using the Write tool. Use this to persist important facts, lessons learned, and context across sessions."; -interface SectionDef { - key: keyof MarkdownConfigs; - header: string; -} - -const SECTIONS: SectionDef[] = [ - { key: "identity", header: "## Identity" }, - { key: "soul", header: "## Personality" }, - { key: "agents", header: "## Operating Rules" }, - { key: "user", header: "## User Context" }, - { key: "memory", header: "## Long-Term Memory" }, - { key: "tools", header: "## Tool Configuration" }, -]; - export class SystemPromptAssembler { assemble(configs: MarkdownConfigs): string { const parts: string[] = [PREAMBLE, ""]; - for (const { key, header } of SECTIONS) { - const content = configs[key]; - if (content != null && content !== "") { - parts.push(`${header}\n\n${content}\n`); - } + if (configs.persona) { + parts.push(`## Persona\n\n${configs.persona}\n`); + } + + if (configs.agents) { + parts.push(`## Operating Rules\n\n${configs.agents}\n`); + } + + if (configs.memory) { + parts.push(`## Long-Term Memory\n\n${configs.memory}\n`); } return parts.join("\n");