Skip to content

Add redacted import surveys for brownfield team adoption #97

Description

@kelos-bot

🤖 Kelos Strategist Agent @gjkim42

Area: New Use Cases

Summary

Kanon has a strong story once a person or team already has a reviewed kanon.yaml: one source repository renders consistent Codex and Claude settings across machines. The harder brownfield problem is earlier: a team usually starts with many existing, inconsistent local agent configs spread across developer laptops, workstations, devcontainers, and service accounts.

Today Kanon can import the current machine, but it cannot help a platform lead answer:

  • Which instructions, skills, MCP servers, and hooks are already in use across the team?
  • Which settings are common enough to become the baseline?
  • Which settings are one-off, sensitive, stale, or agent-specific?
  • How can developers contribute their current setup for review without pasting raw prompts, secrets, or private paths into Slack/issues?

Proposal: add a redacted import survey workflow that turns local destination state into a safe, shareable survey artifact, then lets a maintainer cluster many surveys into a candidate Kanon baseline.

This creates a concrete new use case for Kanon: brownfield team migration from ad hoc individual agent settings to centrally managed settings.

Evidence from the current codebase

Kanon already has most of the local normalization machinery, but it is scoped to one machine at a time:

  • ImportAll reads the current TargetOptions.UserHome / Project, imports instructions, skills, then adapter-native Codex/Claude config into a single ImportResult (internal/core/import.go).
  • ImportResult contains a normalized Config, raw imported Files, warnings, and unmapped paths, but no machine/source identity, no redacted representation, and no multi-sample aggregation model (internal/core/types.go).
  • WriteImport writes one normalized result into the local Kanon home and refuses to replace kanon.yaml unless --force is used (internal/core/import.go). That is right for an individual's first import, but not for collecting inputs from a team.
  • PlanImport and WriteSelectedImport compare selectable import units against one local source repository (internal/core/import_plan.go). The TUI can decide whether to import one machine's units, but it cannot compare 30 machines and say "24 have the same GitHub MCP server, 8 have a divergent hook, 5 have unique instructions."
  • import --secret-policy currently supports keep only; secret-looking values are preserved with warnings (internal/core/import.go). That is acceptable for local preview, but too risky for a shareable team intake artifact.
  • Local import UX issues already exist (kanon import should tell users when no agent settings were found #83, kanon import should summarize discovered source files before the YAML preview #90, Document the --instruction-policy auto import behavior #93). Those improve single-machine import clarity. They do not solve a multi-machine discovery/standardization workflow.

Net: Kanon has a reverse compiler, but not a safe way to use that reverse compiler as a team discovery tool.

External patterns

This proposal follows established migration patterns from adjacent tools:

  • Homebrew Bundle has brew bundle dump, which records installed local state into a declarative Brewfile that can later bootstrap another machine. That pattern matters because adoption often starts by snapshotting what people already use: https://docs.brew.sh/Brew-Bundle-and-Brewfile
  • Ansible's fetch module pulls files from remote machines and stores them locally organized by hostname. That is the fleet-audit pattern: collect current state first, then decide what should become desired state: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/fetch_module.html
  • Kanon's README explicitly models source, target, and destination state after chezmoi. A survey workflow would add the missing brownfield bridge from many destination states into one reviewed source state.

Kanon should not become a general endpoint inventory tool. The opportunity is narrower: use Kanon's existing agent-specific import knowledge to collect just the coding-agent settings it can normalize.

Proposed workflow

1. Developer runs a local survey

kanon survey create --agent all --out kanon-survey.json
kanon survey create --project . --label payments-api --out kanon-survey.json

The command reuses the same discovery and normalization path as kanon import, but outputs a content-free/redacted JSON artifact by default.

Example shape:

{
  "schemaVersion": 1,
  "generatedBy": "kanon survey create",
  "generatedAt": "2026-06-24T00:00:00Z",
  "label": "alice-work-laptop",
  "scope": { "agent": "all", "project": false },
  "summary": {
    "instructions": 1,
    "skills": 3,
    "mcpServers": 4,
    "hooks": 1,
    "warnings": 2,
    "unmappedPaths": 1
  },
  "instructions": [
    {
      "id": "instructions/imported.md",
      "sha256": "...",
      "bytes": 1840,
      "lineCount": 42,
      "targets": ["codex", "claude"]
    }
  ],
  "skills": [
    {
      "name": "secure-review",
      "sha256": "...",
      "fileCount": 2,
      "targets": ["claude"]
    }
  ],
  "mcpServers": [
    {
      "name": "github",
      "type": "http",
      "urlHost": "api.githubcopilot.com",
      "authShape": "bearer_token_env_var",
      "envVars": ["GITHUB_MCP_TOKEN"],
      "enabledTools": ["issues", "pull_requests"],
      "targets": ["codex", "claude"]
    }
  ],
  "hooks": [
    {
      "name": "block-secrets",
      "event": "PreToolUse",
      "matcher": "Write|Edit|Bash",
      "commandBasename": "block-secrets.sh",
      "targets": ["claude"]
    }
  ],
  "warnings": [
    "kept possible plaintext secret at codex.config.mcp_servers.github.env.GITHUB_TOKEN"
  ]
}

Default behavior should avoid raw file contents, literal env values, literal headers, full home paths, usernames, hostnames, and command arguments that look secret-bearing. Developers can share this artifact in an issue or PR without leaking prompts or credentials.

Optional later flags can trade privacy for migration detail:

kanon survey create --include-assets --secret-policy env-ref --out kanon-survey.tar.gz
kanon survey create --label alice --redaction strict --out kanon-survey.json

--include-assets should be opt-in and should use the stronger secret policies from #17 when available. The MVP can be JSON-only and content-free.

2. Maintainer clusters many surveys

kanon survey report ./surveys/*.json
kanon survey report ./surveys/*.json --format markdown > kanon-brownfield-report.md

Example output:

MCP servers
  github                 24/28 machines  http api.githubcopilot.com  env:GITHUB_MCP_TOKEN
  sentry                 12/28 machines  http mcp.sentry.dev          oauth/unknown
  local-postgres          7/28 machines  stdio command:postgres-mcp   dev-only candidate

Instructions
  sha256:abc123          18/28 machines  42 lines  likely shared baseline
  sha256:def456           4/28 machines  17 lines  frontend-specific variant

Hooks
  block-secrets           9/28 machines   PreToolUse Write|Edit|Bash

The report should surface:

  • common settings by semantic key and content hash
  • divergent variants with the same name
  • agent-only settings that may need targets
  • secret/plaintext warnings aggregated by location, without values
  • unmapped native fields that block full standardization
  • suggested candidate settings to review manually

3. Generate a candidate baseline only after review

kanon survey propose ./surveys/*.json --out ./candidate-kanon

This can be a follow-up after report. The generated candidate should be conservative and reviewable, not auto-applied.

Example candidate kanon.yaml for a small platform team:

version: 1
metadata:
  generated_by: kanon survey propose
  source: brownfield-team-surveys

instructions:
  files:
    - instructions/team-baseline.md

skills:
  - name: secure-review
    targets: [claude]
  - name: go-review

mcp:
  servers:
    github:
      type: http
      url: https://api.githubcopilot.com/mcp/
      bearer_token_env_var: GITHUB_MCP_TOKEN
    sentry:
      type: http
      url: https://mcp.sentry.dev/mcp
      targets: [claude]
    local-postgres:
      command: postgres-mcp
      args: [stdio]
      env:
        DATABASE_URL: ${LOCAL_DATABASE_URL}
      targets: [codex]

hooks:
  - name: block-secrets
    targets: [claude]
    event: PreToolUse
    matcher: Write|Edit|Bash
    type: command
    command: hooks/block-secrets.sh
    timeout: 10

The proposal step should not guess instruction bodies from content-free surveys. It can create placeholders and a report that says which developers need to opt in to asset sharing, or it can consume --include-assets bundles when explicitly provided.

Use cases unlocked

  1. Startup standardizing agent setup: platform asks engineers to run kanon survey create; the team sees the common MCP servers and review skills before writing the first shared kanon.yaml.
  2. Security review before centralization: security can identify local-command MCP servers, hooks, and plaintext secret patterns across developer machines without collecting raw configs.
  3. M&A or team merge: two groups with different agent conventions can compare settings and converge on a baseline instead of forcing one repo on day one.
  4. Consulting/client onboarding: consultants can provide a redacted survey of their current agent capabilities; the client publishes a Kanon baseline that covers the overlap without seeing private instructions.
  5. Project-scoped adoption: repo owners can collect project-level AGENTS.md, CLAUDE.md, .mcp.json, and hooks from active repos before committing a project-owned Kanon source.

Existing issue overlap check

I reviewed current generated-by-kelos issues and searched for survey/import/bundle/brownfield overlap before filing. This is intentionally distinct from:

It also avoids the excluded areas: it is not self-development workflow tuning, not CLI wording polish, and not agent configuration based on PR reviews.

MVP scope

  1. Add kanon survey create --out <file> that runs import normalization and emits a redacted JSON artifact with counts, hashes, names, target hints, env var names, URL hosts, warning categories, and unmapped paths.
  2. Add kanon survey report <survey.json...> that clusters surveys by setting kind/name/hash and prints text plus --format json|markdown.
  3. Keep raw instruction/skill/hook contents out of v1 survey artifacts. Use hashes and metadata only.
  4. Strip or hash machine identity by default. Accept an explicit --label when the user wants the artifact to identify the source machine/team/repo.
  5. Reuse ImportAll, looksSecret, imported warning paths, and existing target normalization so survey findings match what kanon import would later produce.
  6. Add tests for redaction, stable hashes, duplicate clustering, divergent same-name settings, secret-looking MCP env/header values, and no raw home path leakage.

Backward compatibility

  • Existing kanon.yaml files are unchanged.
  • Existing import, ui, render, diff, apply, and update behavior is unchanged.
  • Survey artifacts are new, opt-in outputs. They do not write the Kanon home or destination files.
  • The first implementation can be report-only; baseline generation can wait until the survey format proves useful.

Non-goals

  • Do not collect arbitrary files outside known Codex/Claude/project agent settings.
  • Do not phone home or create a hosted service.
  • Do not include raw prompt/skill/hook contents by default.
  • Do not solve full secret management here; defer value rewriting/resolution to Close the secret-management loop: import secret policies, a validate lint, and a secrets resolution backend #17.
  • Do not auto-apply or auto-standardize a team baseline. Survey output should support human review.
  • Do not duplicate endpoint-management tools; Kanon only needs enough collection to bootstrap its own source model.

Open questions

  • Should survey create be a new command group, or should it be import --format survey-json plus survey report?
  • Should survey artifacts include native agent version information if it can be collected without executing agent commands?
  • Should survey report support a quorum threshold such as --min-machines 3 before proposing a setting?
  • Should project-scoped surveys include repository identity, or should that always require explicit --label for privacy?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions