Operations¶
Deployment patterns¶
Long-running daemon¶
- Run under
systemd,tmux, or equivalent supervisor. - Set restart policy to
on-failure.
Tick-based scheduling¶
- Use cron/systemd timer/launchd/OpenClaw.
- Run every 15-30 minutes.
- Pipe JSON output to logs.
Logging¶
- Use JSON output where supported.
- Capture stdout/stderr to centralized logging.
- Track failed loops and repeated skips.
Backup and recovery¶
- Snapshot SQLite DB regularly.
- Back up config and token material securely.
- Validate restore procedure before incident.
tuitbot backup # create backup to ~/.tuitbot/backups/
tuitbot backup --list # list existing backups
tuitbot backup --prune 5 # keep 5 most recent
tuitbot restore ./backup.db # restore with confirmation
tuitbot restore ./backup.db --validate-only # validate only
Pre-migration backups are created automatically on startup when the DB already exists.
Runbooks¶
Step-by-step operational guides are available in docs/runbooks/:
- Incident Response — general triage
- Auth Expiry — token refresh failures
- Rate Limit Storms — circuit breaker events
- Backup & Restore — scheduled backups, recovery
- Database Maintenance — WAL, VACUUM, cleanup
Upgrades¶
tuitbot update
This single command:
- Checks GitHub Releases for a newer
tuitbotbinary. - Downloads, verifies SHA256, and atomically replaces the running binary.
- If
tuitbot-serveris found onPATH, updates it from the same release (non-fatal on failure). - Detects new config features and walks you through adding them.
Use --check to see if an update is available without installing. Use --config-only to skip the binary update. Use --non-interactive in CI to apply config defaults automatically.
Note: If
tuitbot-serverwas installed via Tauri sidecar (not onPATH), it is skipped automatically. If the server is running during update, Unix will succeed (the process keeps its old file descriptor) but Windows may fail — stop the server first.
After updating, run tuitbot test to validate auth and connectivity.
Architecture Layer Guide¶
Tuitbot's core follows a three-layer architecture: Toolkit, Workflow, and Autopilot. Each layer has specific operational characteristics.
Profile Selection Guide¶
Choose the right MCP profile based on your use case:
| Scenario | Recommended Profile | Rationale |
|---|---|---|
| AI agent that reads tweets and scores them | api-readonly |
Full read access + DM reads (45 tools), zero mutation risk |
| Agent that needs config/health checks only | readonly |
Minimal 14-tool surface |
| Growth co-pilot that drafts and queues content | write |
All 112 tools including DMs, content gen, and approval |
| Managing X Ads campaigns | admin |
16 Ads API tools (Admin only) |
| Compliance job management or stream rules | admin |
7 Compliance + Stream Rules tools (Admin only) |
| Debugging raw X API responses | admin |
Universal request tools for ad-hoc endpoints (139 tools total) |
| New integration, testing phase | api-readonly |
Start read-only, upgrade to write after validation |
| Production autonomous agent | write with approval_mode = true |
Human review before posting |
Progression path: Start with readonly or api-readonly to verify connectivity and tool behavior. Graduate to write with dry_run_mutations = true to preview mutations without executing them. Enable live mutations only after reviewing dry-run output.
Safe Mutation Checklist¶
Before enabling mutations for any consumer (MCP agent, automation, CLI):
-
Enable approval mode — all mutations route to the approval queue for human review:
[general] approval_mode = true -
Start with dry-run — mutations are logged but not executed:
[mcp_policy] dry_run_mutations = true -
Set conservative rate limits — default is 20 mutations/hour:
[mcp_policy] max_mutations_per_hour = 10 -
Require approval for critical tools — route specific tools through the queue:
[mcp_policy] require_approval_for = ["x_post_tweet", "x_reply_to_tweet", "x_post_thread"] -
Block tools you don't need — remove tools from the available surface:
[mcp_policy] blocked_tools = ["x_delete_tweet", "x_follow_user", "x_unfollow_user"] -
Review the approval queue before approving:
tuitbot approve --list
Layer-Specific Operational Notes¶
Toolkit layer (core::toolkit/):
- Stateless — safe to call in any context without initialization overhead
- No rate limiting or policy enforcement at this layer
- Errors are typed (ToolkitError) and map directly to MCP error codes
- Use for testing, debugging, and admin operations
Workflow layer (core::workflow/):
- Requires DB connection and optionally LLM provider
- Policy enforcement and safety checks live here
- Composite operations (discover → draft → queue) are deterministic
- All workflow errors propagate through WorkflowError
Autopilot layer (core::automation/):
- Scheduled loops with jitter and circuit breaking
- Loops call workflow and toolkit — never X API directly
- Mode-aware: Autopilot mode runs all loops, Composer mode runs read-only + posting
- Graceful shutdown via CancellationToken
MCP Observability & Quality Gates¶
Telemetry¶
Every MCP tool invocation is recorded in the mcp_telemetry table with:
tool_name— which tool was calledcategory— tool category (composite,composite_mutation,mutation,analytics, etc.)latency_ms— wall-clock execution timesuccess— whether the call succeedederror_code— machine-readable error code on failurepolicy_decision— policy gate outcome (allow,deny,route_to_approval,dry_run)
Query telemetry via MCP tools:
get_mcp_tool_metrics— time-windowed aggregates per tool (call counts, success rates, latency percentiles)get_mcp_error_breakdown— error distribution grouped by tool and error code
Quality Gates¶
The eval harness (cargo test -p tuitbot-mcp eval_harness) enforces two quality gates:
| Gate | Threshold | Description |
|---|---|---|
| Schema validation | >= 95% | All MCP tool responses must conform to the ToolResponse envelope (success key present). As of v1.0, all tools return the envelope. |
| Unknown errors | <= 5% | Error responses must use typed error codes — unclassified errors indicate missing handling |
Running the eval harness:
cargo test -p tuitbot-mcp eval_harness -- --nocapture
This executes three scenarios:
- Scenario A — Raw direct reply: draft a reply and queue it
- Scenario B — Composite flow: find opportunities → draft replies → queue replies
- Scenario C — Policy-blocked mutation: verify denied calls are captured in telemetry
Results are written to docs/roadmap/artifacts/task-07-eval-results.json and task-07-eval-summary.md.
CI Integration¶
Add to your CI pipeline after the standard test suite:
# Quality gates (fail build if thresholds breached)
cargo test -p tuitbot-mcp eval_harness
The eval harness asserts quality gates directly — test failure means a gate was breached.
MCP Profile Verification Runbook¶
Use this runbook to verify MCP profile integrity after deployments, profile changes, or CI failures.
1. Quick Profile Smoke Test¶
Confirm each profile exposes the expected number of tools:
# Write profile (expect 112)
cargo run -p tuitbot-cli -- mcp manifest --profile write --format json | jq '.tool_count'
# Admin profile (expect 139)
cargo run -p tuitbot-cli -- mcp manifest --profile admin --format json | jq '.tool_count'
# Read-only profile (expect 14)
cargo run -p tuitbot-cli -- mcp manifest --profile readonly --format json | jq '.tool_count'
# API read-only profile (expect 45)
cargo run -p tuitbot-cli -- mcp manifest --profile api-readonly --format json | jq '.tool_count'
2. Confirm Read-Only Guarantee¶
Verify that read-only profiles contain zero mutation tools:
# Both should output 0
cargo run -p tuitbot-cli -- mcp manifest --profile readonly --format json \
| jq '[.tools[] | select(.mutation == true)] | length'
cargo run -p tuitbot-cli -- mcp manifest --profile api-readonly --format json \
| jq '[.tools[] | select(.mutation == true)] | length'
3. Verify Manifest Sync¶
Ensure committed manifests match the current binary output:
bash scripts/check-mcp-manifests.sh
# Expected: exit 0, "All manifests in sync."
If drift is detected, regenerate: bash scripts/generate-mcp-manifests.sh
4. CI Gate Reference¶
| Gate | What it validates | Local run command |
|---|---|---|
| Boundary tests (32+) | Profile isolation, mutation denylists, lane constraints | cargo test -p tuitbot-mcp boundary |
| Conformance tests | 27 kernel + 31 spec conformance tools with correct schemas | cargo test -p tuitbot-mcp conformance |
| Golden snapshots | Response schema drift detection | cargo test -p tuitbot-mcp golden_snapshot_matches |
| Eval harness | 4 scenarios × 4 quality gates | cargo test -p tuitbot-mcp eval_harness |
| Manifest sync | Committed JSON matches binary output | bash scripts/check-mcp-manifests.sh |
5. Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Wrong tool count | Tool added/removed without profile update | Update router.rs profile registration, re-run boundary tests |
| Mutation tool in read-only | Tool incorrectly tagged or registered | Check is_mutation() in tool definition, verify profile exclusion |
| Manifest drift | Binary updated but manifests not regenerated | Run bash scripts/generate-mcp-manifests.sh and commit |
| Boundary test failure | Profile invariant violated | Read test assertion message — it names the exact tool/profile mismatch |