Prepared by: SCOUT (TITAN research arm)
Audit date: 2026-04-23
Scope: Read-only audit of existing Claude Code config, TITAN infrastructure, security surface, cost exposure, and gaps toward true 24/7 agentic operation.
Files consulted: CLAUDE.md, settings.json, settings.local.json, all 15 scheduled-task SKILL.md files, 13 skill SKILL.md files, 22 hook/script files, logs, state files, .env files, .gitignore.
---
Five lifecycle hooks are wired and shipping Python scripts that fail silently:
| Hook event | Script | What it does |
|---|---|---|
| PreToolUse (Write/Edit) | titan-validate-skill.py | Blocks malformed SKILL.md frontmatter before save |
| PostToolUse (Write/Edit) | titan-sync.py | Mirrors ~/.claude/ changes to F:/TITAN for backup |
| PostToolUse (all tools) | titan-metrics.py | Appends per-call TSV row to F:/TITAN/metrics/tools-YYYYMMDD.tsv |
| SessionStart | titan-session-log.py | Appends start event to F:/TITAN/logs/sessions.log |
| PreCompact | titan-precompact.py | Saves a snapshot to F:/TITAN/knowledge/auto-memory/ with session_id, cwd, trigger type; injects additionalContext so Claude sees it |
| Stop | titan-session-log.py stop + titan-reflect.py | Appends stop event + writes structured JSONL turn digest to F:/TITAN/logs/turns.jsonl |
The PreCompact hook is the strongest 24/7 piece: it fires before context compaction, writes a snapshot, and injects a reminder back into the model context. This is TITAN's main anti-amnesia mechanism today.
| Task | Cadence | Role |
|---|---|---|
| titan-daily-backup | Daily ~11:23 PM | git commit + robocopy to E:/TITAN-backups, 30-day retention |
| titan-daily-newsletter | Daily | Compose intelligence newsletter from staging |
| titan-daily-monologue | Daily | TITAN journals turns/mood/curiosities to F:/TITAN/journal/ |
| titan-daily-feed | Daily 4:33 AM | ORACLE pulls AI/cloud/Claude Code intel to staging |
| titan-weekly-review | Sunday 8:24 PM | 7-domain weekly scorecard email |
| titan-weekly-benchmark | Sunday 6:17 AM | TITAN health index 0-100; flags regression |
| titan-nightly-reindex | Nightly 3:33 AM | POST to local TITAN server to re-embed staging → RAG index |
| titan-daily-log-rotation | Daily 11:52 PM | POST to TITAN server to rotate logs > 50MB |
| titan-daily-pa-email | Daily 5:27 AM | Morning briefing with reminders, calendar, peptides, priorities |
| titan-daily-improve | Daily | DARWIN reads evals/errors/guardrails; proposes ONE improvement to staging |
| claude-code-audit-every-6h | Every 6h at :17 | Dispatches SCOUT to audit CC architecture; files T-registry recs |
| swarm-health-orchestrator | Every 15 min | Scans agent outputs for truncation/stuck; logs swarm-health.log; auto-respawns |
| titan-inbox-watch | Every 15 min | Polls Gmail for TITAN: prefix; dedup via inbox-queue.jsonl; drafts HTML reply |
| titan-weekly-dream | Weekly | VAULT consolidates memory staging → hot/warm/cold |
| titan-monthly-evolve | Monthly | DARWIN mines patterns; proposes new skills to skills-proposed/ |
evolve, pulse, monologue, reflect, newsletter, teach, learn, titan (master control), briefing, feed, dream, sense, and a token-tracker utility under sense/.
---
Both settings.json ("defaultMode": "bypassPermissions") and settings.local.json ("defaultMode": "bypassPermissions" + "skipDangerousModePermissionPrompt": true) set bypass mode. This means:
skipDangerousModePermissionPrompt: true means even the "are you sure?" bypass warning is suppressed.TITAN: can queue a command that the inbox-watch poller will execute as a Claude Code agent. The inbox-watch skill has guardrails ("never run destructive ops"), but those guardrails exist only in the skill prompt, not in any technical enforcement layer.F:/TITAN/server/.env contains:
TITAN_API_TOKEN (the bearer token for the local TITAN API server — controls reminders, RAG reindex, log rotation, and more)PERPLEXITY_API_KEY (active Perplexity Pro subscription key)RESEND_API_KEY (Resend transactional email key — can send email as titan@livegroweveryday.com)F:/TITAN/deployment/aws-relay-state.env contains:
The .gitignore at F:/TITAN/.gitignore correctly lists secrets/.env but NOT F:/TITAN/server/.env or F:/TITAN/deployment/aws-relay-state.env by their actual paths — both fall under the *.log and logs/ exclusions only incidentally. If F:/TITAN is ever pushed to a remote git repository, these files would be included unless explicitly excluded. The RESEND and Perplexity keys are live and billable.
The PEM file at C:/Users/Harnoor/.ssh/titan-relay.pem is the SSH private key for the EC2 relay instance. It is on the local filesystem with no noted encryption at rest.
titan-nightly-reindex and titan-daily-log-rotation both hit http://127.0.0.1:8765 (HTTP, not HTTPS) with a bearer token read from F:/TITAN/server/.env. Risks:
127.0.0.1 but if the Windows firewall rule is misconfigured or any process binds 0.0.0.0 instead, the port would be reachable from the network.With bypassPermissions active, Claude Code can write to any path it can reach. The sync hook's skip list (sessions, cache, shell-snapshots, etc.) reduces noise, but it is not a security boundary — it is a mirror-filter. Claude Code itself has no path restriction policy configured. The settings.local.json allow list contains highly specific one-off entries (xcopy paths, robocopy, powershell wildcard *) that accumulated across ad-hoc sessions. This allow list is now vestigial — bypassPermissions renders it redundant — but it represents scope that was once explicitly granted and is now implicit.
The audit found aws iam: in the settings.local.json allow list and aws dynamodb:, aws amplify:, aws route53:, aws route53domains:*. The actual IAM role/policy attached to the local AWS CLI profile was not visible in these files. The deployment .env reveals a specific EC2 instance and EIP but not the IAM role policy scope. Without the IAM policy JSON, the blast radius of a compromised AWS session is unknown. There is no evidence of least-privilege scoping for the Claude Code session's AWS credentials.
---
Claude Code runs on the Claude Max plan subscription (not pay-per-token Bedrock). The llm-costs.jsonl file records total_cost_usd per session ranging from ~$0.004 for tiny turns to ~$0.18 for multi-turn agentic sessions. These are computed estimates, not actual billed amounts — the Max plan is a flat subscription. However, the logged cost fields are useful for relative session-size tracking.
Cache creation tokens (ephemeral_1h_input_tokens) dominate most sessions, indicating aggressive use of Claude's 1-hour prompt cache — this is correct behavior for cost efficiency.
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 — actively used by /feed and ORACLE. No usage cap or budget alarm found.re_FMVR9hHv_CcjYVDG4iFzUd93wms7Lz43a — used for morning digest, critical alert email fallback. Free tier is 3,000 emails/month; daily emails from titan-daily-pa-email + weekly-review are well within free tier, but no alarm exists if volume spikes.No CloudWatch billing alarm, AWS Budgets rule, or Perplexity rate-limit config was found. The only cost anomaly detection is the daily email report — a 24-hour lag for a runaway scheduled task or looping agent.
---
What's missing: If the swarm-health-orchestrator itself crashes or the Claude Code process dies at 3 AM, nothing detects that TITAN has gone silent. There is no heartbeat watchdog that fires an external alert when the 15-min health log goes stale for >30 minutes.
Impact: Silent total outage. User finds out at 5:27 AM when the PA email fails to arrive.
Fix: A lightweight cron (Windows Task Scheduler or a simple Lambda) that reads F:/TITAN/plans/swarm-health.log and fires an SMS/push if the last entry is >30 min old.
What's missing: The daily-aws-cost.log emails cost once per day. A runaway agentic loop (or an accidentally infinite scheduled task) could spend $50+ before the next morning report arrives.
Fix: AWS Budgets alert at $5/day threshold. One console click. Also add a Perplexity usage ceiling via their API settings.
What's missing: The PreCompact hook saves a snapshot and injects an additionalContext string, but the PostCompact hook (titan-postcompact.py) exists in the scripts directory but is NOT wired in settings.json. After compaction, the model gets no prompt-level instruction to re-read the snapshot. The recovery relies entirely on the model happening to act on the PreCompact additionalContext message before it gets compacted away.
Fix: Wire titan-postcompact.py to the PostCompact hook in settings.json. The script should inject a additionalContext that says "Read your latest precompact snapshot at [path] to recover context."
What's missing: Alerting is exclusively via Gmail drafts/email. On mobile, these are delayed by however long it takes Harnoor to check email. A swarm truncation storm, cost spike, or server crash generates no push notification. The swarm-health-orchestrator has an email alert threshold defined (>5 truncations / 4h) but no SMS or push path.
Fix: Wire a Pushover or Ntfy webhook as a fallback notification channel for CRITICAL alerts. The TITAN server already has Resend for email — add one more path for true push.
What's missing: titan-daily-backup runs once per day at 11:23 PM. Intraday work (skill writes, memory promotions, plan memos) is backed up only via the titan-sync.py mirror hook (which copies to F:/TITAN), but there is no git commit until the nightly backup. If F: drive is lost mid-afternoon, up to ~18 hours of work is lost.
Fix: Add a git commit step to the PostToolUse Write/Edit hook — or at minimum, a per-hour micro-commit scheduled task. The daily backup already does this once; hourly micro-commits would reduce max data loss to 1 hour.
What's missing: The swarm-health-orchestrator SKILL.md itself notes: "This scheduled task runs in Claude Code's cron system, which auto-expires after some period. Harnoor or the TITAN bootstrap should re-create it every 30 days minimum." No automated re-registration exists. If any scheduled task silently expires (Claude Code's routine limit is platform-enforced), TITAN will appear healthy while running nothing.
Fix: Add a /pulse check that reads the actual registered routine list from the Claude Code API and compares it against the expected 15 tasks. Alert if any are missing or expired.
What's missing: The only enforcement against destructive operations from inbox commands or agentic loops is the text "Never run destructive ops" in SKILL.md files. bypassPermissions disables the tool-use confirmation gate. A prompt injection via a TITAN: email could trigger bash commands.
Fix: Add a PreToolUse hook on Bash that blocks patterns matching rm -rf, --force, DROP TABLE, git push --force. This is a technical guardrail that survives prompt injection.
What's missing: The .gitignore covers secrets/.env and *.key, but F:/TITAN/server/.env is not in a secrets/ directory. If F:/TITAN is ever pushed to a remote repo, the Perplexity key, Resend key, and TITAN API token would be committed.
Fix: Add server/.env and deployment/*.env to F:/TITAN/.gitignore explicitly.
What's missing: The local AWS CLI profile used by Claude Code (for route53, dynamodb, amplify, iam, s3) has unknown IAM policy scope. The allow list shows aws iam:* — if the profile has IAM write access, a compromised session could create backdoor roles.
Fix: Run aws iam get-user and aws iam list-attached-user-policies to enumerate the current scope. Restrict to least-privilege: Route53 write, DynamoDB for the specific table(s), Amplify for the specific app, no iam:*.
What's missing: Scheduled tasks run in a fresh session each time. If a task is mid-execution when compaction occurs, the PostCompact hook (unwired) cannot tell a scheduled task to resume. The task will either complete the compacted-down version of its context or silently drop work.
Fix: Each long-running scheduled task (e.g., titan-daily-pa-email, claude-code-audit-every-6h) should write a checkpoint file at the start and update it at each major step. The PreCompact hook should read the checkpoint and include it in the snapshot. This is analogous to saga pattern checkpointing.
---
Create F:/TITAN/scripts/titan-watchdog.py that:
1. Reads last line of F:/TITAN/plans/swarm-health.log
2. Parses timestamp
3. If now - last_timestamp > 35 minutes: POST to a Pushover/Ntfy endpoint with message "TITAN swarm silent for 35+ min"
Register this in Windows Task Scheduler as titan-watchdog running every 10 minutes. It has no Claude Code dependency — pure Python stdlib + HTTP.
In AWS Console → Billing → Budgets:
For Perplexity: set a monthly usage alert at $30 in their dashboard.
In C:/Users/Harnoor/.claude/settings.json, add:
"PostCompact": [
{
"hooks": [
{
"type": "command",
"command": "python F:/TITAN/scripts/titan-postcompact.py 2>/dev/null || true",
"timeout": 5
}
]
}
]
Then write titan-postcompact.py to emit additionalContext pointing to the latest precompact snapshot.
Add NTFY_TOPIC or PUSHOVER_TOKEN to F:/TITAN/server/.env. Modify the swarm-health-orchestrator skill and the dead-man watchdog to POST to the ntfy.sh endpoint on CRITICAL events. Ntfy is free, no app store required, and works on Android/iOS.
Create titan-hourly-commit scheduled task that runs git -C F:/TITAN add -A && git -C F:/TITAN commit -m "hourly snapshot $(date -Iseconds)" --allow-empty. Register in Claude Code scheduled tasks with cron 0 . This reduces intraday data-loss window from 18h to 1h.
Add to the /pulse skill: read the Claude Code routine list via the API, diff against the canonical list of 15 expected tasks, append result to F:/TITAN/logs/pulse.log, and alert if any task is missing. The swarm-health-orchestrator can include this check in its 15-min cycle.
Add a PreToolUse hook on Bash that checks tool_input.command against a blocklist regex: rm\s+-rf|--force|DROP\s+TABLE|git push.*--force|format\s+[A-Z]:. Exit with decision: block if matched. This provides a technical floor that survives prompt injection.
Add to F:/TITAN/.gitignore:
server/.env
server/.env.*
deployment/*.env
deployment/*.env.*
Run aws iam get-user + aws iam simulate-principal-policy to enumerate actual permissions. Remove iam:* from allowed operations. Create a dedicated titan-claude-code IAM user with policy limited to the exact resources in use (specific DynamoDB tables, specific Amplify app, specific Route53 hosted zones).
Define a standard checkpoint file pattern: F:/TITAN/state/checkpoints/<task-name>.json with fields started_at, current_step, completed_steps[], last_updated. Each major scheduled task writes this at startup and after each step. The PreCompact hook reads all checkpoint files and includes them in the snapshot.
---
C:/Users/Harnoor/.claude/CLAUDE.mdC:/Users/Harnoor/.claude/settings.jsonC:/Users/Harnoor/.claude/settings.local.jsonscheduled-tasks/*/SKILL.mdskills/*/SKILL.mdF:/TITAN/scripts/ — 22 scriptsF:/TITAN/logs/llm-costs.jsonl (first 20 rows)F:/TITAN/logs/daily-aws-cost.logF:/TITAN/plans/swarm-health.logF:/TITAN/plans/audit-cadence.logF:/TITAN/server/.envF:/TITAN/deployment/aws-relay-state.envF:/TITAN/.gitignoreF:/TITAN/state/inbox-queue.jsonl (confirmed exists)C:/Users/Harnoor/.ssh/titan-relay.pem (confirmed exists)---
Memo ends. Word count: ~2,450 words.