Veille System — Full Audit
ODS Innovation · Daily Technology Watch · 2026-04-07
The veille is ODS Platform's autonomous daily tech watch — scanning releases, CVEs, trending repos, and tools relevant to the stack. It runs at 07:00 UTC via systemd timer, producing structured JSON+HTML findings with Slack notifications and Google Drive sync. This audit covers 15 days of operation (Mar 23–Apr 7) across all system components.
How It Works
The veille system is a three-layer architecture: a bash dispatcher triggered by systemd injects commands into a Claude Code tmux session, which spawns a specialized veille agent. The agent uses WebSearch/WebFetch to scan 19 dependencies, GitHub advisories, and trending repos. Outputs are written deterministically via CLI tools (write-finding.sh and write-daily-summary.sh) that produce validated JSON and ODS-branded HTML. Results are synced to Google Drive and posted to Slack #Innovation.
Daily Run & Ad-Hoc Flows
Ctrl/Cmd + wheel to zoom. Drag to pan. Double-click to fit.
System Components
| Component | Path | Role | Health |
|---|---|---|---|
| Agent Definition | ~/.claude/agents/veille.md | Agent instructions (405 lines) | OK |
| Dispatcher | ~/dev/ops/innovation/scripts/dispatcher-innovation.sh | Daily orchestrator (160 lines) | OK |
| Slack Bridge | ~/dev/ops/innovation/scripts/innovation-slack-bridge.sh | Slack poller (30s interval) | OK |
| write-finding.sh | ~/dev/ops/adlc-v2/scripts/cli/write-finding.sh | Per-finding JSON+HTML writer | OK |
| write-daily-summary.sh | ~/dev/ops/adlc-v2/scripts/cli/write-daily-summary.sh | Daily aggregation JSON+HTML | WarnEmpty HTML on 2 days |
| SystemD Timer | ~/.config/systemd/user/ods-innovation.timer | Trigger (daily 07:00 UTC) | Active |
| SystemD Service | ~/.config/systemd/user/ods-innovation.service | Runs dispatcher | OK |
| Innovation Bridge Skill | ~/.claude/skills/innovation-bridge/SKILL.md | Routes Slack commands | OK |
| last-versions.json | ~/dev/ops/innovation/last-versions.json | 19 tracked dependencies | OK |
| reviewed-repos.json | ~/dev/ops/innovation/reviewed-repos.json | 40 repos tracked | OK |
| 10 components audited | 8 OK · 1 Warn · 1 Active | ||
Daily Run History
| Date | Findings | Summary JSON | Summary HTML | Status |
|---|---|---|---|---|
| 2026-03-23 | Yes | Yes | Yes | Done |
| 2026-03-24 | Yes | Yes | Yes | Done |
| 2026-03-25 | Yes | Yes | Yes | Done |
| 2026-03-26 | Yes | No | No | No summary |
| 2026-03-27 | Yes | Yes | 0 bytes | Empty HTML |
| 2026-03-28 | Yes | Yes | Yes | Done |
| 2026-03-29 | Yes | Yes | 0 bytes | Empty HTML |
| 2026-03-30 | Yes | Yes | Yes | Done |
| 2026-03-31 | Yes | Yes | Yes | Done |
| 2026-04-01 | 14 | Yes | Yes | Done |
| 2026-04-02 | 15 | Yes | Yes | Done |
| 2026-04-03 | 13 | Yes | Yes | Done |
| 2026-04-04 | 33 | Yes | Yes | Done |
| 2026-04-05 | 0 | No | No | Failed |
| 2026-04-06 | 10 | Yes | Yes | Done |
| 2026-04-07 | 0 | No | No | Stalled 3h+ |
| 16 days tracked (Mar 23 – Apr 7) | 13 OK · 1 failed · 2 partial | |||
Must Fix Immediately
- Status file says RUNNING since 07:02:32 UTC, but no findings directory created
- The dispatcher injected at 07:02, but the
ods-claudetmux session was restarted at 10:07 (after injection). The command was lost. - Impact: Today's entire tech watch is missing
- Fix: Add a watchdog — if veille status is RUNNING for >2 hours with no findings, post alert to Slack DM and re-trigger
- Findings directory exists but is empty (0 findings). No daily summary generated.
- Dispatcher log:
"already triggered for 2026-04-05 — skipping"— a review status file existed before the dispatcher ran - Apr 6 dispatcher:
"no summary found for 2026-04-05" - Root cause: Agent was triggered ad-hoc (status set to TRIGGERED), but never completed
- Fix: Dispatcher should check for completion (not just trigger status). Distinguish TRIGGERED vs COMPLETED.
~/dev/ops/innovation/findings/+daily/— canonical (from CLI tools)~/dev/ops/reports/veille/—veille-YYYY-MM-DD.json/html~/dev/ops/reports/veille-YYYY-MM-DD.json/html— no subdirectory~/dev/ops/veille/reports/— yet another schema
Fix: Consolidate to
~/dev/ops/innovation/ only. Update agent definition and CLI tools.
Significant Problems
2026-03-27-summary.html and 2026-03-29-summary.html are 0 bytes. JSON summaries exist and are valid. Root cause: write-daily-summary.sh's Python HTML generation redirects stdout to file — if Python crashes, the file is created empty. Fix: Verify HTML >0 bytes after generation; regenerate if empty.
Read ~/dev/ops/innovation/agents/veille.md. But the actual agent file is at ~/.claude/agents/veille.md. The Claude agent spawner reads from ~/.claude/agents/ automatically. Fix: Update dispatcher line 71 to remove the incorrect path reference.
Improvements
M1: No cron fallback for systemd timer
5 7 * * * bash ~/dev/ops/innovation/scripts/dispatcher-innovation.sh
M2: Missing Mar 26 summary — never generated
write-daily-summary.sh 2026-03-26 to backfill.
M3: Fragile Slack JSON construction
write-daily-summary.sh use inline Python for Slack JSON. Line 221 passes "$MSG" with unescaped newlines. Special characters in finding titles could break the JSON. Fix: Use python3 -c "import json; print(json.dumps(...))" consistently.
M4: Summary generated before veille agent runs
dispatcher-innovation.sh line 80 runs write-daily-summary.sh RIGHT AFTER triggering the veille agent, before findings are produced. The summary is based on old/no data. Fix: Remove line 80. Let the agent call it at the end of its run.
M5: Agent memory scattered across 8+ locations
.claude/agent-memory/veille/ exists under home, dev, and 4+ project directories with different MEMORY.md content. Agent learning doesn't consolidate. Fix: Centralize to ~/.claude/agent-memory/veille/MEMORY.md.
L1: No retry enforcement on GitHub API rate limits
L2: No GDrive sync validation
rclone exit code is checked but no validation that files arrived. Low priority — rclone is reliable.L3: reviewed-repos.json has no schema validation
15-Day Assessment
| Metric | Value | Assessment |
|---|---|---|
| Days with findings produced | 13/15 (87%) | Good |
| Days with complete summary (JSON+HTML) | 11/15 (73%) | Needs work |
| Days with all outputs correct | 10/15 (67%) | Needs work |
| SystemD timer active | Yes | Good |
| Avg findings per day | ~12 | Good |
| Dependencies tracked | 19 | Good |
| Repos reviewed | 40 | Good |
| Slack notifications | Working | Good |
| GDrive sync | Working | Good |
| Duplicate output locations | 4 dirs | Bad |
| Watchdog / alerting | None | Bad |
| 11 metrics reviewed | 7 Good · 2 Warn · 2 Bad |
Priority Order
- Add completion watchdog — cron every 30min that checks for stalled runs, alerts and re-triggers
- Consolidate output directories — single canonical location
~/dev/ops/innovation/ - Fix dispatcher line 80 — don't generate summary before agent runs
- Fix dispatcher line 71 — correct agent path reference
- Add empty-file detection — verify HTML >0 bytes in write-daily-summary.sh
- Add cron fallback — for systemd timer redundancy
- Backfill missing summaries — run write-daily-summary.sh for Mar 26
- Centralize agent memory — single ~/.claude/agent-memory/veille/MEMORY.md
- Harden Slack JSON — use json.dumps() consistently for all Slack payloads