- Add start.bas with ADD SWITCHER keywords (tables, list, cards) - Remove /opt/gbo/data references from AGENTS.md and INFRA.md - Bots are stored in MinIO drive, not in /opt/gbo/data - Update infrastructure paths documentation
12 KiB
General Bots AI Agent Guidelines
- For host/infra operations see INFRA.md (container ops, Vault, CI/CD, DNS, MinIO, alerts)
- stop saving .png on root! Use /tmp. never allow new files on root.
- never push to alm without asking first - it is production!
- NEVER deploy to production manually — ALWAYS use CI/CD pipeline
- NEVER include sensitive data (IPs, tokens, passwords, keys) in any documentation
- NEVER use scp or manual deployment to system container
- ALWAYS push to ALM → CI builds on alm-ci → CI deploys automatically
- 8080 is server, 3000 is client UI
- Test web: http://localhost:3000 (botui!)
- Test login: http://localhost:3000/suite/auth/login.html
- DEV ENV — sometimes pasting from PROD, do not treat as prod. Just fix, push to CI.
- Use Playwright MCP to start localhost:3000/botname now.
- NEVER create files with secrets in repository root
- Mask IPs in logs (10.x.x.x pattern, not real IPs)
- NEVER use cargo clean — causes 30min rebuilds, use ./reset.sh for DB issues
- Secret files go in /tmp/ only (vault-token-gb, vault-unseal-key-gb)
- See botserver/src/drive/local_file_monitor.rs for how bots load from drive (MinIO)
WORKSPACE STRUCTURE
| Crate | Purpose | Port | Tech |
|---|---|---|---|
| botserver | Main API server, business logic | 8080 | Axum, Diesel, Rhai BASIC |
| botui | Web UI server (dev) + proxy | 3000 | Axum, HTML/HTMX/CSS |
| botapp | Desktop app wrapper | - | Tauri 2 |
| botlib | Shared library | - | Core types, errors |
| botbook | Documentation | - | mdBook |
| bottest | Integration tests | - | tokio-test |
| botdevice | IoT/Device support | - | Rust |
| botplugin | Browser extension | - | JS |
Key Paths: target/debug/botserver | botserver/.env | botui/ui/suite/
CHAT FLOW
- WebSocket connect → UserSession created, session_id generated
- start.bas runs ONCE per session → ADD_SUGGESTION calls, Redis flag set
- Message processing → if type 6: TOOL_EXEC (bypass LLM), else: KB injection + LLM
- Tool Execution → Direct .ast via Rhai, no LLM/KB
- LLM Response → Streaming via WebSocket chunks
- Frontend Display → HTMX, suggestion buttons from Redis
Message Types: 0=EXTERNAL 1=USER 2=BOT_RESPONSE 3=CONTINUE 4=SUGGESTION 5=CONTEXT_CHANGE 6=TOOL_EXEC
Bots live in drive (MinIO storage), each bucket is a bot. Respect LOAD_ONLY.
BASIC SCRIPT ARCHITECTURE
- start.bas — Runs once per session, loads suggestions
- tables.bas — Parsed at compile time, defines DB schema (DO NOT CALL with CALL)
- tool.bas — Compiled to .ast, executed via CALL or TOOL_EXEC type 6
BASIC Keywords — Syntax Signatures (no quotes, bare tokens)
TALK message | HEAR prompt AS variable | USE KB name | CLEAR KB USE WEBSITE url | ADD SUGGESTION text | CLEAR SUGGESTIONS GET FROM table WHERE condition | SAVE record TO table | FIND value IN table FIRST(array) | LAST(array) | COUNT(array) | FORMAT template, var1, var2 CREATE FILE path WITH content | READ FILE path | WRITE FILE path WITH content DELETE FILE path | COPY FILE source TO dest | LIST FILES path UPLOAD data TO path | DOWNLOAD url TO path GET HTTP url | POST HTTP url WITH data | WEBHOOK url WITH data CREATE_TASK title, assignee, due, project_id | WAIT seconds ON EMAIL FROM filter DO CALL handler | ON CHANGE table DO CALL handler SET BOT MEMORY key = value | GET BOT MEMORY key | REMEMBER key = value SET CONTEXT key = value | SET USER property = value | TRANSFER TO HUMAN ADD BOT name WITH TRIGGER phrase | DELEGATE TO name | SEND TO BOT name MESSAGE msg SEND MAIL TO email WITH subject, body | SEND SMS TO phone MESSAGE text CREATE DRAFT title WITH content | CREATE SITE name WITH config POST TO SOCIAL platform MESSAGE text | LLM prompt DETECT tablename | CALL scriptname
Built-in Variables: TODAY, NOW, USER, SESSION, BOT
Full keyword docs: botbook/src/04-basic-scripting/
SECURITY DIRECTIVES — MANDATORY
- Error Handling: NO unwrap/expect/panic/todo/unimplemented. Use value? or ok_or_else
- Command Execution: Use SafeCommand, never Command::new directly
- Error Responses: Use log_and_sanitize, never raw error strings to clients
- SQL: Use sql_guard sanitize_identifier/validate_table_name, never format strings
- Rate Limiting: governor crate, per-IP and per-User, WebSocket 10 msgs/s
- CSRF: All state-changing endpoints need CSRF token (exempt: Bearer Token APIs)
- Security Headers on ALL responses: CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy
- Dependency Pinning: Critical deps exact version, track Cargo.lock for app crates
Full security docs: botbook/src/09-security/
MANDATORY CODE PATTERNS
- Use Self in impl blocks, not MyStruct
- Derive PartialEq + Eq together
- format!(name) not format!({}, name)
- Combine identical match arms: A | B => thing()
ABSOLUTE PROHIBITIONS
- NEVER search /target folder (binary compiled)
- NEVER hardcode credentials — use generate_random_string() or env vars
- NEVER build in release mode or use --release flag
- NEVER run cargo build — use cargo check
- NEVER deploy manually — always push to ALM, CI/CD deploys
- NEVER use scp/SSH to deploy — CI workflow handles it
- NEVER use cargo clean — causes 30min rebuilds
- NEVER use panic/todo/unimplemented/Command::new/unwrap/expect
- NEVER use #[allow()] — FIX the code
- NEVER add lint exceptions to Cargo.toml
- NEVER prefix unused vars with _ — DELETE or USE them
- NEVER leave unused imports or dead code
- NEVER use CDN links — all assets local
- NEVER comment out code — DELETE it
- NEVER create .md files without checking botbook/ first
- NEVER write internal IPs to logs — mask as 10.x.x.x
FILE SIZE LIMIT: 450 LINES MAX
Split at 350 lines proactively: types.rs, handlers.rs, operations.rs, utils.rs, mod.rs
ERROR FIXING WORKFLOW
OFFLINE FIRST: Read ALL errors → group by file → fix ALL per file → write once → verify LAST NEVER run cargo check DURING fixing — fix ALL offline, verify ONCE at end Streaming Build Rule: Cancel build as soon as first errors appear, fix immediately
MEMORY MANAGEMENT
If Killed during compile: pkill -9 cargo; pkill -9 rustc; pkill -9 botserver Then: CARGO_BUILD_JOBS=1 cargo check -p botserver 2>&1 | tail -200
RESET PROCESS
reset.sh cleans and restarts dev env. Bootstrap takes 3-5 min. If timeout: check botserver.log for Bootstrap process completed Manual: ps aux | grep botserver | grep -v grep; curl http://localhost:8080/health; ./restart.sh Verify: PostgreSQL 5432, Valkey 6379, BotServer 8080, BotUI 3000
PLAYWRIGHT BROWSER TESTING
- Navigate to http://localhost:3000/botname
- Take snapshot → test flows → verify results → validate backend
- Desktop may have maximized chat — click middle button to minimize
- Backend validation: psql or tail logs after UI interactions
ADDING NEW FEATURES
- Add types to botlib if shared
- Add migration SQL + Diesel model
- Add business logic in botserver/src/features/
- Add API endpoint
- Add BASIC keyword if needed (register_custom_syntax, spawn thread for async)
- Security: input validation, auth, rate limit, sanitize errors, no unwrap
Architecture details: botbook/src/02-architecture-packages/architecture.md
BUG FIXING
- Reproduce: grep errors in botserver.log, trace data flow
- Find code: grep -r pattern --include=*.rs, check mod.rs
- Fix minimal: wrong variable? missing validation? race condition?
- Test: cargo check -p botserver, ./restart.sh, verify in browser
- Commit: clear message with root cause, impact, files, testing notes
Logs: check container logs via sudo incus exec system -- journalctl -u botserver | botserver.log (dev only) | botui.log | [drive_monitor] prefix | CLIENT: prefix
On staging/production: check logs in container via sudo incus exec system -- tail -f logs/err.log
Troubleshooting: botbook/src/12-ecosystem-reference/troubleshooting.md
DEPLOY WORKFLOW
Push to ALM → CI builds on alm-ci → deploys to system container via SSH NEVER deploy manually. CI path: alm-ci builds → tar+gzip → /opt/gbo/bin/botserver → restart CI deploy: alm-ci at /opt/gbo/bin/botserver → SSH → system container Runner: gbuser uid 1000, workspace /opt/gbo/data/, SSH key /home/gbuser/.ssh/id_ed25519
CI/CD details: botbook/src/12-ecosystem-reference/ci-cd.md
PRODUCTION CONTAINER ARCHITECTURE
| Container | Service | Port |
|---|---|---|
| system | BotServer + Valkey | 8080/6379 |
| vault | Vault | 8200 |
| tables | PostgreSQL | 5432 |
| drive | MinIO | 9000/9100 |
| directory | Zitadel | 9000 |
| meet | LiveKit | 7880 |
| vectordb | Qdrant | 6333 |
| llm | llama.cpp | 8081 |
| Stalwart | 993/465/587 | |
| alm | Forgejo | 4747 (NOT 3000!) |
| alm-ci | Forgejo Runner | - |
| proxy | Caddy | 80/443 |
| dns | CoreDNS | 53 |
Container ops: sudo incus list/start/stop/restart/exec/snapshot Backup: pg_dump -U postgres -F c -f /tmp/backup.dump dbname ALM port is 4747. Runner token in action_runner_token table.
Container details: botbook/src/02-architecture-packages/containers.md Backup/Recovery: botbook/src/12-ecosystem-reference/backup-recovery.md
PRODUCTION OPERATIONS — QUICK REFERENCE
Critical Safety Rules
- NEVER modify iptables without explicit confirmation
- NEVER touch PROD without asking first
- ALWAYS backup files to /tmp before editing
Infrastructure Paths
- Base: /opt/gbo/ | Bin: /opt/gbo/bin | Conf: /opt/gbo/conf | Logs: /opt/gbo/logs
- Bots are stored in MinIO (drive), NOT in /opt/gbo/data
Service Operations
- DNS (CoreDNS): config /opt/gbo/conf/Corefile, zones in MinIO
- PostgreSQL: backup pg_dump, restore pg_restore
- Email (Stalwart): config /opt/gbo/conf/config.toml, check DKIM TXT records
- Proxy (Caddy): config /opt/gbo/conf/config, validate then reload
- MinIO: internal API http://drive-ip:9000, bots stored as buckets
- Bot System: binary /opt/gbo/bin/botserver, Valkey port 6379
- ALM (Forgejo): port 4747, CI runner separate container, token from DB
- CI Runner: config /opt/gbo/bin/config.yaml, runs as gbuser, systemd service sccache at /usr/local/bin/sccache, workspace /opt/gbo/data/
Network — NAT Port Forwarding
External ports DNAT to container IPs via iptables. Rules in /etc/iptables.rules Always use external interface (-i iface) to avoid loopback issues.
Port Map: 53=DNS 80/443=HTTP/HTTPS 5432=PostgreSQL 993=IMAPS 465=SMTPS 587=Submission 4747=Forgejo 9000=MinIO 8200=Vault
Container Management
sudo incus list | start/stop/restart container | exec container -- bash sudo incus snapshot create container name | copy container/snapshot target
Troubleshooting
- Container won't start: sudo incus list, sudo incus log container --show-log
- Service not running: sudo incus exec container -- pgrep -a process
- Email delivery: check stalwart, IMAP/SMTP ports, DKIM records
- Disk space: df -h, sudo btrfs filesystem df /var/lib/incus
Full operations: botbook/src/02-architecture-packages/containers.md
STAGING ENVIRONMENT (STAGE-GBO)
Use 10.0.3.x subnet for container IPs. Route via host gateway 10.0.0.1. Do NOT confuse staging (10.0.3.x) with production ranges.
FRONTEND STANDARDS
HTMX-first: hx-get, hx-post, hx-target, hx-swap. No CDN. All assets local.
UI details: botbook/src/07-user-interface/htmx-architecture.md
PERFORMANCE & LINTING
- Clippy: 0 warnings. No #[allow()] — fix code
- Release profile: opt-level=z, lto=true, codegen-units=1, strip=true, panic=abort
- Weekly: cargo tree --duplicates, cargo machete, cargo audit
TESTING
- Unit tests: inline #[cfg(test)] modules or crate tests/ dir
- Integration tests: bottest/ crate, cargo test -p bottest
- Coverage: 80%+ for critical paths, ALL error paths, ALL security guards
Testing details: botbook/src/12-ecosystem-reference/architecture.md
CONTINUATION PROMPT
- Check build/diagnostics
- Fix ALL warnings and errors — no #[allow()]
- Delete unused code
- Replace ALL unwrap/expect with proper error handling
- Verify after each fix batch
- Loop until 0 warnings, 0 errors
- Refactor files >450 lines
MEMORY DIRECTIVES
OFFLINE FIRST → BATCH BY FILE → WRITE ONCE → VERIFY LAST → DELETE DEAD CODE Push to ALL remotes (github, pragmatismo)
SECRET FILES — /tmp/ ONLY
vault-token-gb and vault-unseal-key-gb go in /tmp/ only — cleared on reboot, not tracked by git.