feat(audit): add append-only agent audit trail (.beads/interactions.jsonl)

Implements audit logging for agent interactions to support auditing and
dataset generation (fixes #649).

New features:
- .beads/interactions.jsonl (append-only audit log)
- bd audit record: log LLM calls, tool calls, or pipe JSON via stdin
- bd audit label <id>: append labels (good/bad) for dataset curation
- bd compact --audit: optionally log LLM prompt/response during compaction
- bd init: creates empty interactions.jsonl
- bd sync: includes interactions.jsonl in staging

Audit entries are append-only - labeling creates new entries that
reference parent entries by ID.

Closes #649

Co-authored-by: Dmitry Chichkov <dchichkov@nvidia.com>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-20 03:24:51 -08:00
parent 3c08e5eb9d
commit 7b758271ed
10 changed files with 483 additions and 45 deletions

View File

@@ -195,6 +195,16 @@ With --stealth: configures global git settings for invisible beads usage:
}
}
// Create empty interactions.jsonl file (append-only agent audit log)
interactionsPath := filepath.Join(beadsDir, "interactions.jsonl")
if _, err := os.Stat(interactionsPath); os.IsNotExist(err) {
// nolint:gosec // G306: JSONL file needs to be readable by other tools
if err := os.WriteFile(interactionsPath, []byte{}, 0644); err != nil {
fmt.Fprintf(os.Stderr, "Error: failed to create interactions.jsonl: %v\n", err)
os.Exit(1)
}
}
// Create metadata.json for --no-db mode
cfg := configfile.DefaultConfig()
if err := cfg.Save(beadsDir); err != nil {
@@ -234,6 +244,16 @@ With --stealth: configures global git settings for invisible beads usage:
fmt.Fprintf(os.Stderr, "Warning: failed to create/update .gitignore: %v\n", err)
// Non-fatal - continue anyway
}
// Ensure interactions.jsonl exists (append-only agent audit log)
interactionsPath := filepath.Join(beadsDir, "interactions.jsonl")
if _, err := os.Stat(interactionsPath); os.IsNotExist(err) {
// nolint:gosec // G306: JSONL file needs to be readable by other tools
if err := os.WriteFile(interactionsPath, []byte{}, 0644); err != nil {
fmt.Fprintf(os.Stderr, "Warning: failed to create interactions.jsonl: %v\n", err)
// Non-fatal - continue anyway
}
}
}
// Ensure parent directory exists for the database
@@ -1555,7 +1575,6 @@ Aborting.`, yellow("⚠"), dbPath, cyan("bd list"), prefix)
return nil // No database found, safe to init
}
// landingThePlaneSection is the "landing the plane" instructions for AI agents
// This gets appended to AGENTS.md and @AGENTS.md during bd init
const landingThePlaneSection = `
@@ -1608,17 +1627,17 @@ func updateAgentFile(filename string, verbose bool) error {
// File doesn't exist - create it with basic structure
newContent := fmt.Sprintf(`# Agent Instructions
This project uses **bd** (beads) for issue tracking. Run ` + "`bd onboard`" + ` to get started.
This project uses **bd** (beads) for issue tracking. Run `+"`bd onboard`"+` to get started.
## Quick Reference
` + "```bash" + `
`+"```bash"+`
bd ready # Find available work
bd show <id> # View issue details
bd update <id> --status in_progress # Claim work
bd close <id> # Complete work
bd sync # Sync with git
` + "```" + `
`+"```"+`
%s
`, landingThePlaneSection)