Skip to content

Latest commit

 

History

History
234 lines (203 loc) · 10.8 KB

File metadata and controls

234 lines (203 loc) · 10.8 KB

SecOps Agent Development Guide

Project Overview

SecOps Agent is an independent Crush fork maintained by chenchunrun and built on top of the original project by Charm. It connects to LLMs and gives them tools to read, write, and execute code. It supports multiple providers (Anthropic, OpenAI, Gemini, Bedrock, Copilot, Hyper, MiniMax, Vercel, and more), integrates with LSPs for code intelligence, and supports extensibility via MCP servers and agent skills.

The module path is github.com/chenchunrun/SecOps.

Architecture

main.go                            CLI entry point (cobra via internal/cmd)
internal/
  app/app.go                       Top-level wiring: DB, config, agents, LSP, MCP, events
  cmd/                             CLI commands (root, run, login, models, stats, sessions)
  config/
    config.go                      Config struct, context file paths, agent definitions
    load.go                        crush.json loading and validation
    provider.go                    Provider configuration and model resolution
  agent/
    agent.go                       SessionAgent: runs LLM conversations per session
    coordinator.go                 Coordinator: routes by agent id (coder, task, planner, ops, sec)
    handoff/                       Crush Handoff v1: parse, validate, extract from Markdown
    pending_handoff.go             Pending handoff from UI session history → prompt prefix + audit
    prompts.go                     Loads Go-template system prompts
    templates/                     System prompt templates (coder.md.tpl, task.md.tpl, etc.)
    tools/                         All built-in tools (bash, edit, view, grep, glob, etc.)
      mcp/                         MCP client integration
  session/session.go               Session CRUD backed by SQLite
  message/                         Message model and content types
  db/                              SQLite via sqlc, with migrations
    sql/                           Raw SQL queries (consumed by sqlc)
    migrations/                    Schema migrations
  lsp/                             LSP client manager, auto-discovery, on-demand startup
  ui/                              Bubble Tea v2 TUI (see internal/ui/AGENTS.md)
  permission/                      Tool permission checking and allow-lists
    secops_permission.go           SecOps risk-aware permission decision chain
  security/
    capability.go                  Capability-based gate model
    risk_assessment.go             Multi-factor risk assessment engine
    attack/                        Reduced ATT&CK corpus + evidence reasoner
    redact/                        Shared credential-redaction patterns (used by
                                   audit/SIEM export and the shell command log)
  audit/
    audit.go                       Audit event model and service
    audit_store.go                 Persistent audit storage
    compliance_report.go           Compliance report generation
    siem_export.go                 SIEM exporters (redaction delegated to security/redact)
  computer/                        Stable Computer identity, lifecycle, and backend adapters
  sandbox/
    executor.go                    Local/Docker/SSH execution backend
  skills/                          Skill file discovery and loading
  shell/                           Bash command execution with background job support
  event/                           Telemetry (PostHog)
  pubsub/                          Internal pub/sub for cross-component messaging
  filetracker/                     Tracks files touched per session
  history/                         Prompt history
  integration/                     End-to-end integration tests
  agent/tools/secops/              SecOps tool implementations (18 categories)

Project Docs

Public docs/ content should stay limited to stable guides and legal/licensing materials.

Process records, validation logs, release-closeout notes, and working security documents should remain local-only. These are intentionally excluded from the public repository through .gitignore rules for docs/project/, docs/release/, docs/security/, and LOCAL_* materials unless intentionally reclassified for publication.

Key Dependency Roles

  • charm.land/fantasy: LLM provider abstraction layer. Handles protocol differences between Anthropic, OpenAI, Gemini, etc. Used in internal/app and internal/agent.
  • charm.land/bubbletea/v2: TUI framework powering the interactive UI.
  • charm.land/lipgloss/v2: Terminal styling.
  • charm.land/glamour/v2: Markdown rendering in the terminal.
  • charm.land/catwalk: Snapshot/golden-file testing for TUI components.
  • sqlc: Generates Go code from SQL queries in internal/db/sql/.

Key Patterns

  • Config is a Service: accessed via config.Service, not global state.
  • Tools are self-documenting: each tool has a .go implementation and a .md description file in internal/agent/tools/.
  • Fixed tool families use toolset builders: when adding a fixed built-in agent tool, prefer extending an existing Build*ToolSet(...) dataset or adding a new dataset-backed toolset in internal/agent/tools/ instead of appending raw constructors in coordinator.buildTools.
  • System prompts are Go templates: internal/agent/templates/*.md.tpl with runtime data injected.
  • Context files: Crush reads AGENTS.md, CRUSH.md, CLAUDE.md, GEMINI.md (and .local variants) from the working directory for project-specific instructions.
  • Planner agent id: planner is its own agent entry (AgentPlanner), not a Task profile switch. Defaults to read-only tools (glob, grep, ls, sourcegraph, view), no bash or SecOps execution; use options.active_agent or /planner in the TUI.
  • Crush Handoff v1 (agent-to-agent): Producers embed Handoff JSON in a Markdown fenced code block labeled crush-handoff (see internal/agent/handoff). Logic in pending_handoff.go; for consumers coder, task, ops_agent, and security_expert_agent, SessionAgent.Run lifts the newest valid pending handoff (after the last user message in history) into promptPrefix via handoff.FormatForPrompt. Each injection is recorded as audit event agent_handoff_consumed (EventTypeAgentHandoffConsumed), including details such as handoff_version and source_assistant_message_id.
  • Persistence: SQLite + sqlc. All queries live in internal/db/sql/, generated code in internal/db/. Migrations in internal/db/migrations/.
  • Pub/sub: internal/pubsub for decoupled communication between agent, UI, and services.
  • Computer boundary: internal/computer owns stable logical IDs and lifecycle state. Local, Docker, and SSH are adapters behind that boundary; provider SDK types must not enter the core Computer model.
  • CGO disabled: builds with CGO_ENABLED=0 and GOEXPERIMENT=greenteagc.

Build/Test/Lint Commands

  • Module and build caches: If downloads from proxy.golang.org time out or sandbox permission interferes with the default Go cache, point caches at repo-local directories (both are gitignored):
GOMODCACHE="$(pwd)/.gomodcache" GOCACHE="$(pwd)/.gocache" go test ./...
GOMODCACHE="$(pwd)/.gomodcache" GOCACHE="$(pwd)/.gocache" go build .
  • Build: go build . or go run .
  • Test: task test or go test ./... (run single test: go test ./internal/llm/prompt -run TestGetContextFromPaths). Handoff + audit regression: go test ./internal/agent -run 'TestPendingHandoff|TestRecordHandoff' -count=1
  • Update Golden Files: go test ./... -update (regenerates .golden files when test output changes)
    • Update specific package: go test ./internal/tui/components/core -update (in this case, we're updating "core")
  • Lint: task lint:fix
  • Format: task fmt (gofumpt -w .)
  • Modernize: task modernize (runs modernize which makes code simplifications)
  • Dev: task dev (runs with profiling enabled)

Code Style Guidelines

  • Imports: Use goimports formatting, group stdlib, external, internal packages.
  • Formatting: Use gofumpt (stricter than gofmt), enabled in golangci-lint.
  • Naming: Standard Go conventions — PascalCase for exported, camelCase for unexported.
  • Types: Prefer explicit types, use type aliases for clarity (e.g., type AgentName string).
  • Error handling: Return errors explicitly, use fmt.Errorf for wrapping.
  • Context: Always pass context.Context as first parameter for operations.
  • Interfaces: Define interfaces in consuming packages, keep them small and focused.
  • Structs: Use struct embedding for composition, group related fields.
  • Constants: Use typed constants with iota for enums, group in const blocks.
  • Testing: Use testify's require package, parallel tests with t.Parallel(), t.SetEnv() to set environment variables. Always use t.Tempdir() when in need of a temporary directory. This directory does not need to be removed.
  • JSON tags: Use snake_case for JSON field names.
  • File permissions: Use octal notation (0o755, 0o644) for file permissions.
  • Log messages: Log messages must start with a capital letter (e.g., "Failed to save session" not "failed to save session").
    • This is enforced by task lint:log which runs as part of task lint.
  • Comments: End comments in periods unless comments are at the end of the line.

Testing with Mock Providers

When writing tests that involve provider configurations, use the mock providers to avoid API calls:

func TestYourFunction(t *testing.T) {
    // Enable mock providers for testing
    originalUseMock := config.UseMockProviders
    config.UseMockProviders = true
    defer func() {
        config.UseMockProviders = originalUseMock
        config.ResetProviders()
    }()

    // Reset providers to ensure fresh mock data
    config.ResetProviders()

    // Your test code here - providers will now return mock data
    providers := config.Providers()
    // ... test logic
}

Formatting

  • ALWAYS format any Go code you write.
    • First, try gofumpt -w ..
    • If gofumpt is not available, use goimports.
    • If goimports is not available, use gofmt.
    • You can also use task fmt to run gofumpt -w . on the entire project, as long as gofumpt is on the PATH.

Comments

  • Comments that live on their own lines should start with capital letters and end with periods. Wrap comments at 78 columns.

Committing

  • ALWAYS use semantic commits (fix:, feat:, chore:, refactor:, docs:, sec:, etc).
  • Try to keep commits to one line, not including your attribution. Only use multi-line commits when additional context is truly necessary.

Working on the TUI (UI)

Anytime you need to work on the TUI, read internal/ui/AGENTS.md before starting work.