Skip to content

Latest commit

 

History

History
211 lines (195 loc) · 13.3 KB

File metadata and controls

211 lines (195 loc) · 13.3 KB

Changelog

All notable changes to AOH. Format: Keep a Changelog, versioning: SemVer.

[Unreleased]

Added

  • v0.3 phase B — authoring/promote (SDD, commits be42725494e4cf, 365 tests):

    • aoh skill promote <name> [--from DIR] --pack <name> [--pr]: promotes a locally-drafted skill (found via .claude/skills/<name> or .agents/skills/<name>, searched upward from cwd, or an explicit --from) into a git-hosted pack. Direct-commit is the default (bare-mirror → fresh temp worktree cut from a freshly-fetched default branch → full pack validation in the worktree → commit → fast-forward push to the real repo); --pr is opt-in (feature branch skill/<name> pushed to the real repo, gh pr create). Prints the staged diff (git diff --cached) before announcing success. A no-op re-promote (unchanged skill) is detected via git's own "nothing to commit" and reported without a duplicate commit. A non-fast-forward push rejection (someone else promoted in between) surfaces as PromoteError with "re-run with --pr" — never auto-retried, never force-pushed.
    • src/aoh/gitops.py write primitives: fetch_default_branch (re-resolves origin/HEAD fresh every call, falling back to main/master), create_worktree/remove_worktree, check_identity (fails fast if user.name/user.email aren't configured), commit_all, push_fast_forward, create_branch, push_branch (pushes to the real remote by URL, not the mirror), set_remote_url, staged_diff, open_pr (shells out to gh pr create).
    • src/aoh/skillcopy.py (new): hygiene-filtered skill tree copy — rejects .git directories, symlinks, devices/sockets/fifos, and oversized files; enforces MAX_FILE_BYTES (10 MiB/file), MAX_TOTAL_BYTES (50 MiB/skill), MAX_FILE_COUNT (500 files) in a single pre-scan pass, so any violation leaves the destination completely untouched (no partial copy).
    • src/aoh/promote.py (new): orchestrates discover → copy-hygiene → worktree → validate → commit/PR, wrapping git and copy-hygiene failures as PromoteError (distinct from PackError, which stays for genuine pack validation failures).
    • collections/core/aoh-authoring pack: one skill (author-and-promote-skill) that walks an agent through confirming a draft validates standalone, identifying the target pack from ~/.aoh/config.yaml, running scripts/promote.sh (a thin exec aoh skill promote "$@" wrapper), reading the staged diff before it ships, and reporting the result — states the secrets-honesty contract explicitly ("AOH does not intentionally manage secrets").
    • Live validation evidence: docs/demos/promote-validation-2026-07-19.md — real, private, throwaway GitHub repo (never the real agenticdevops/aoh), proving direct-commit promote, no-op re-promote, and a real merged --pr PR, including an honestly-recorded open_pr bug found during the live run.
  • v0.3 phase A — fleet inventory, lock, convergent installs (SDD, commits 9750a3c3e657df, 307 tests):

    • kind: UserConfig (~/.aoh/config.yaml, lazy-loaded — every command still works with no config present): named pack sources, site: pointer, named registries: (placeholder for v0.3 phase C), defaults.runtime, defaults.model, tri-state defaults.workspaceRoot.
    • kind: Site (site.yaml): advisory workspaceRoot, defaults (runtime/model) split from targetDefaults, structured packs: ({repo, subdir, ref} or a bare local path string), groups: with shared vars, bindingsDir: (one level, sorted, filename stem must equal metadata.name, symlinked dir or files rejected, duplicate names rejected). Binding gained optional spec.pack / spec.group / spec.runtime fields.
    • kind: SiteLock (site.lock.yaml, committed next to site.yaml): per-pack {repo, subdir, requestedRef, resolvedCommit} (or {local: true, path}). aoh lock initializes entries that don't yet exist and never silently moves an existing one; aoh lock --update [<pack>] is the only mover and requires --yes (or interactive confirmation) on a source/ref change.
    • src/aoh/gitops.py: bare-mirror git cache keyed by a normalized-URL hash under $AOH_HOME/cache, fcntl-locked (ensure_mirror); export_tree preflights git ls-tree for symlink/submodule entries before any extraction, extracts into a private temp dir, verifies containment, then atomically renames onto the destination; source_checkout caches exports by <urlhash>-<commit>-<subdirhash>-<format> with a .complete marker written last (an incomplete export dir is wiped and re-exported).
    • src/aoh/manifest.py + src/aoh/installer.py: every install now writes aoh-manifest.json (source, resolved commit, per-file content hashes, canonical→materialized artifact map + adapter transform id, owned-file list, namingScheme). Installs are crash-safe and convergent: materialize into a staging dir, write a write-ahead journal (.aoh-journal.json, phase stagedcommitting, fsync'd at each transition) before touching the real workspace, back up every replaced/removed owned file, then commit; an interrupted install recovers to either "nothing happened" (phase staged) or "the new install completed" (phase committing, rolls forward) on the next run. Locally modified owned files refuse the install unless --discard-local is passed. ALL install paths — the legacy single-shot aoh install --runtime … --output … (recorded with namingScheme: v1-legacy) and the new site fan-out — route through the same install_workspace.
    • Site-qualified RBAC naming: bindings installed via a site fan-out get ServiceAccount/ClusterRoleBinding names of the form aoh-<site>-<binding> (DNS-1123 + 63-char validated); standalone (site-less) bindings keep the legacy aoh-<binding> name. Manifest records namingScheme (v2-site-qualified | v1-legacy).
    • `aoh install --site [--group ] [--binding ] [--workspace-root ] [--accept-site-root] [--discard-local]`: fan-out install across every (or a filtered subset of) site bindings, each into `//`. Requires a lock that agrees with `site.yaml`'s source/ref (missing or disagreeing lock → error naming `aoh lock`). Per-binding failures are caught and isolated — other bindings still install, exit 1 if any failed.
    • aoh list [--site <dir>] [--workspace-root <dir>]: fleet table — binding, role, pack@ref, runtime, context/namespace, access, workspace path, provisioned state, credential state (from aoh-provision.json expiry). --site falls back to UserConfig.site when omitted.
    • aoh config init|get|set <dotted.key> [value]: manage ~/.aoh/config.yaml (or $AOH_HOME/config.yaml).
    • aoh lock [--site <dir>] [--update [<pack>]] [--yes]: resolve every site pack ref to a commit and write/update site.lock.yaml.
    • src/aoh/paths.py: safe_segment/safe_join — every workspace-relative path (bindings dir entries, manifest ownedFiles/artifactMap, journal stagingDir/backupDir) is validated as non-escaping before use; nothing path-like from a manifest or journal is trusted without going through it.
    • AOH_HOME env var respected by every command that touches config, cache, or exports (defaults to ~/.aoh).

Changed

  • Adapter contract standardized: RuntimeAdapter.materialize writes into EXACTLY request.output_dir for all three adapters (Hermes, Claude Code, Codex); the Hermes CLI's historical <output>/<profile>/ nesting is now computed in the CLI handler before calling materialize, not inside the adapter. AdapterResult gained artifact_map (canonical pack-relative path → materialized path) and transform_id (e.g. identity-v1, codex-ops-rename-v1); generated_files is now a complete walk of every regular file under the output directory, not just pack-sourced ones.

  • RuntimeAdapter Protocol (materialize(MaterializeRequest) -> AdapterResult) + ADAPTERS registry, extracted from the Hermes adapter — src/aoh/adapters/base.py.

  • Claude Code runtime adapter: self-contained workspace (.claude/skills, .claude/commands/ops/<skill>.md/ops:<skill>, .claude/agents/<role>.md, .claude/settings.json permission deny/allow + PreToolUse guardrail hook, CLAUDE.md).

  • Codex runtime adapter: self-contained workspace (.agents/skills/ops-<skill>/ with frontmatter name rewritten, invoked $ops-<skill>, AGENTS.md, .codex/config.toml, best-effort .codex/rules/kubectl-readonly.rules execpolicy guardrail with documented bypass gaps).

  • aoh install --runtime <hermes|claude-code|codex> <pack> --output <dir> — unified CLI entrypoint into ADAPTERS[<runtime>].materialize(...); old install-hermes* subcommands remain as unchanged compat handlers, install-hermes-agent prints a stderr deprecation hint.

  • Binding.access: scoped | inherit (default scoped); inherit mode materializes a credential-free kubeconfig-overlay via prepare-overlay.sh (resolves cluster/user names from a redacted kubectl config view, never --raw; writes no credentials; self-verifies via --minify and a credential-shape grep).

  • Live validation evidence: docs/demos/adapter-validation-2026-07-16.md — real kind-sresquad-demo cluster run proving the scoped RBAC boundary, the auth can-i matrix (including the get secrets → no flip), codex execpolicy check proofs for both caught and gap-form commands, and adversarial Claude Code hook proofs.

  • docs/adapters.md: runtime adapters reference — workspace layouts, threat model, access modes, guardrail mapping per runtime.

  • Documentation site (Docusaurus) — Concepts/Getting Started/Tutorials/Reference + Field Notes blog; GH Pages deploy.

  • collections/core/kubeops pack: pod-crashloop-triage, pending-pod-triage, node-notready-triage, k8s-service-health-report skills + kubeops-copilot role.

  • Minimal kind: Binding (role × target, open target map), loaded standalone from site repos — examples/sresquad-site/ shows the shape.

  • aoh install-hermes-agent --binding <yaml>: materializes the binding — generates provision.sh (dedicated read-only RBAC identity: get/list/watch), a scoped kubeconfig, KUBECONFIG wiring in launch.sh, and a binding block in SOUL.md.

  • Demo walkthrough: docs/demos/kubeops-readonly.md (safe agentic harness showcase).

Changed (BREAKING — spec v1alpha2)

  • apiVersion is now openagentix.io/v1alpha2; v1alpha1 packs are rejected with a migration pointer. No compatibility shim.
  • Removed kind: Workflow. Multi-skill workflows became process skills (platform-sre-triage, devops-release-automation, mlops-training-triage); single-skill wrappers were deleted. A stale workflows/ dir is a validation error.
  • Renamed agents/roles/ and kind: AgentRolekind: Role; roles no longer carry a workflows: field. A stale agents/ dir is a validation error.
  • Eval now requires spec.skill pointing at the skill it tests.
  • Hermes adapter generates one command per skill, namespaced ops-<skill>.md (canonical name ops:<skill>; separator mapping is per-adapter).
  • Installed skill reference renamed references/aoh-workflow.mdreferences/aoh-pack.md.

Changed (BREAKING — RBAC allowlist)

  • ClusterRole aoh-readonly narrowed from a wildcard read grant (apiGroups: ["*"], resources: ["*"], verbs: [get, list, watch]) to an explicit resource allowlist sized to the kubeops skills (core/apps/batch/metrics/events.k8s.io kinds, get/list/watch only). secrets, configmaps, nodes/proxy, pods/exec, pods/attach, pods/portforward, serviceaccounts/token, RBAC objects, and certificatesigningrequests are explicitly excluded. Shared by every runtime adapter via src/aoh/adapters/_k8s.py::render_provision_script. Any previously provisioned identity still has the old wildcard grant — re-run provision.sh for each existing binding to pick up the narrower allowlist (it updates the ClusterRole in place; verified live: auth can-i get secrets flips from yes to no, see docs/demos/adapter-validation-2026-07-16.md).

Changed

  • Validator: progressive disclosure — only AOH.yaml + at least one skill are mandatory; workflows, agents, teams, models, evals, runtime-requirements are opt-in

Added

  • .planning/ project memory system (GSD-compatible) + CLAUDE.md session protocol
  • planning-context skill (.claude/skills/planning-context)

[0.1.0] - 2026-07-13

Added

  • AOH pack format (AOH.yaml + skills/workflows/agents/teams/models/ runtime-requirements/evals) with referential-integrity validator
  • CLI: validate, init-pack, adapt-hermes, install-hermes, install-hermes-agent, install-hermes-team
  • Hermes runtime adapter: generates config.yaml, SOUL.md, aoh-agent.json, launch.sh, profile-local skills, team manifests
  • Example pack examples/acme-platform-ops (platform-ops team, 3 roles, 5 skills)
  • Core collection collections/core/docker-disk-cleanup (first vertical slice)
  • Authoring skill authoring-skills/create-aoh-pack