Skip to content

Releases: mrobinson2/AzureAgentForge

v1.8.2 — agent identity resolves, governor starts on a fresh deploy

Choose a tag to compare

@mrobinson2 mrobinson2 released this 21 Jul 12:59
22eaa81

v1.8.1 shipped agent peer identity. Deploying it to a real Azure environment found four defects — two in identity, two in the memory-governor's first-ever enable on a fresh subscription. Each is fixed here with a test that catches it without needing a deploy.

Identity was inert

  • PAPERCLIP_AGENT_SLUG was never set — anywhere (#134). Upstream gives a spawned agent a UUID and company id, no slug; nothing in this repo supplied one. The memory helpers key identity off that variable, so every agent's writes collapsed onto a single fallback peer. The adapter patch now derives the slug from the agent's display name using the convention watchdog/roster.py and governor/profiles.py already share, and fails the build if its anchor disappears.
  • The fallback peer held system write authority (#134). That fallback was operator, which maps to the SYSTEM profile — write: ALL_CLASSES. An agent whose identity failed to resolve did not merely lose attribution, it inherited unrestricted write authority, with admission's can_write check running against the wrong, more privileged identity. Now unknown-agent, deliberately absent from DEFAULT_PROFILES so it lands on least-privilege SPECIALIST.

The governor could not start on a fresh deployment

  • Its image shipped without the migrations it applies on boot (#135), so feature_flags was never created and every flag lookup threw UndefinedTableError. Worse, apply() called that success — the live boot logged schema up to date (0 known) seconds before the first error. An absent or empty directory now raises. Same PR: dev now passes memory_governor_image_tag/watchdog_image_tag, which it never did, so enabling the governor no longer falls back to an unpublished latest.
  • The migration chain contradicted itself (#136): 0003 seeds feature_flags.updated_by, a column its own 0001 never created — it exists only in the separate infrastructure/migrations chain. Fixed with an idempotent ALTER ordered ahead of the first INSERT, plus contract tests pinning that every column a later INSERT uses is created earlier in the same chain.

Both deployment paths, same inputs

Self-hosted parity (#133). The Mac-mini stack now takes the same three inputs as Azure — HONCHO_USER_PEER_ID / HONCHO_AGENT_PEER_IDS / HONCHO_PEER_ALIASES in .env versus the matching Terraform variables. Same strings, same parsing; a roster is portable verbatim. deploy/mac-site/README.md carries the warning specific to that topology: both sites share one managed PostgreSQL, so peer ids that differ between them fragment an identity across a failover. Forge Console, installer/core.py, AI-ASSISTED-SETUP.md (new Phase 9b) and terraform.tfvars.example updated to match.

Verified against the deployed artifacts

Not just CI: all five migrations applying on a fresh database with no UndefinedTable/UndefinedColumn errors; the deployed governor image run with the live container's env classifying the declared roster correctly (researcher/cost-guardian/watchdogknown_agent, usercanonical_user, operator and a per-channel peer → unexpected); and the slug injection present in the deployed paperclip image's compiled execute.js.

Suites: memory-governor 234, installer 93, skills 11, paperclip node 17.

Upgrading

No manual migrations — the governor applies its own overlay on startup, which is now possible for the first time. If you enable memory_governor_enabled, pin the governor and watchdog image tags. Identity resolution runs inside admission, so it takes effect where governed memory is enabled (MEMORY_CLASSES_ENABLED); deploying this release does not turn that on.

Full notes: docs/releases/v1.8.2.md

v1.8.1 — agent peer identity + the identity map at admission

Choose a tag to compare

@mrobinson2 mrobinson2 released this 21 Jul 11:06
ee17f3a

v1.8.0 shipped the canonical user peer: one deploy-time input naming the human principal. That answers "who is the human." It does not answer "which peers are legitimate agents" — so an unexpected-peer check could only say not the human, which is true of every legitimate agent self-lesson and therefore useless.

v1.8.1 adds the agent half of that expected set, plus the identity map that folds known strays into the canonical identity as they arrive.

What's new

Two optional deploy-time inputs. Both default to empty, and empty behaves exactly as before:

Input Meaning
HONCHO_AGENT_PEER_IDS Comma-separated agent slugs that are legitimate peers alongside the canonical user
HONCHO_PEER_ALIASES Comma-separated alias=canonical pairs (e.g. operator=user), applied at /admit

At the governor's admission choke point, observer / observed / created_by_peer are each resolved through the alias map and classified canonical_user / known_agent / unexpected / undeclared_roster. Aliases are rewritten before anything reads the peers, so an alias never reaches storage, the dedup lookup, or a downstream event payload. Anything rewritten or unexpected emits a memory_identity event on the agent_events spine.

This is item 1 of the production backstop described in memory-system.md §18. Item 2, the periodic re-consolidation sweep, remains designed and unimplemented.

Three deliberate choices

  • Report, never reject. An unexpected peer is a config smell, not an attack. Refusing the write loses the memory while the misconfiguration that produced it is still in place.
  • Permissive when undeclared. No roster set means nothing is called a stray — an alert that fires on every write is an alert nobody reads.
  • Fail open on bad config. A malformed alias pair is skipped rather than fatal; this runs at the write choke point. Alias resolution is one hop, so a cyclic config (a=b,b=a) terminates instead of hanging admission.

Agent self-lessons stay exempt from the canonical-user rule and are now provably so: a declared agent observing itself classifies as known_agent and emits nothing.

Upgrading

No migrations, no behavior change on default settings. The memory-governor is off by default (memory_governor_enabled), so a default deployment is unaffected either way.

Discover the peers your deployment actually holds with pc-honcho list-peers before declaring a roster — it should describe what is really there, not what you intended.

Verification

16 new offline tests (tests/memory-governor/test_agent_identity.py); full governor suite 229 passed; 24/24 CI checks green including local-stack-smoke.

Full notes: docs/releases/v1.8.1.md

v1.8.0 — deploy-path repair after the v1.7 hardening

Choose a tag to compare

@mrobinson2 mrobinson2 released this 21 Jul 10:27
1d37d9c

The v1.8 line continues in v1.8.1, which adds agent peer identity and the identity map at admission — the agent half of the canonical-peer work. It is not contained in this tag; it landed after v1.8.0 was cut. If you are adopting v1.8, take v1.8.1.

A repair release, not a feature one. v1.7 hardened the platform's security posture; applying that hardening to a real subscription then broke the paths that install and update it. Every item here is a defect found by running the thing, plus the guard that makes it fail loudly next time.

No new features, no new flags, no migrations. If your environment is deployed and healthy, v1.8 changes what happens the next time you build an image, seed a vault, or deploy from scratch.

Deploy-path repair

  • Fresh deploys work again after the Deny-by-default firewalls (#122). A clean-subscription apply died mid-Pass-2 with ForbiddenByFirewall on the Key Vault data sources and a 403 on file-share reads — after plan-time reads had succeeded, so it failed with billable resources standing. Azure Container Apps is not a Key Vault trusted service, so an IP allowlist alone never covers in-VNet callers: the app subnet now carries Microsoft.KeyVault/Microsoft.Storage service endpoints and is allowlisted. Storage ip_rules rejects /32. PostgreSQL 15 names the throttling parameter connection_throttle.enable.
  • The paperclip image is buildable again (#128). scripts/build-and-push.sh hardcoded its own copy of the vendored PaperClip pin, which stopped matching the Dockerfile at the v2026.707.0 bump — and --build-arg beats an ARG default, so every build silently cloned the old upstream and then aborted on a workspace package that version does not ship. Both values now come from one place.
  • CI green again (#127, #130). Two gitleaks false positives in docs/notes/, allowlisted with condition = "AND" so only those literals are exempt and only there.

Drift guards

  • A DSN whose user is not the server admin now fails at seed time (#129). Postgres answers a username mismatch with FATAL: password authentication failed for user "..." — the message names the password and sends you to the wrong secret. In the reference deployment that cost a six-day outage. seed-keyvault.sh now validates both DSN secrets against the expected administrator_login, including values kept from an earlier run, which is the path the drift actually took. Offline --self-check runs it in CI.

Dependencies

  • services/honchopython:3.14-slim-bookworm (#125), reversing the v1.7 revert now that local-stack-smoke passes on 3.14; astral-sh/uv 0.11.29 (#126); actions/setup-node 7 (#123).
  • The services/paperclip 3.14 bump (#124) is not in this release — its smoke job still fails.

Scope note

The v1.7 tag was cut 2026-07-11, before the reliability-hardening merges (#112#117) reached main. Those are documented under the v1.7 milestone and are contained in this tag; the v1.8 notes cover only what is new since that documentation.

Full notes: docs/releases/v1.8.0.md

v1.7.0 — security hardening, governance examples, Foundry chat sample, governor features

Choose a tag to compare

@mrobinson2 mrobinson2 released this 12 Jul 00:00
1fea383

v1.7.0 — release notes

v1.7.0 is the largest AzureAgentForge release so far, measured the only way that
is checkable: by the number of substantive, independent things it ships. This
document enumerates them. Four governor features found and fixed against a real
corpus, a security-remediation batch spanning ~27 findings across seven
subsystems, three new self-contained example/sample packages, and a full
docs refresh — fifteen enumerated items in total, grouped below.

Every runtime addition ships with its feature flag seeded off. Applying this
release to a running system changes nothing until you turn a flag on and apply
the listed migrations. The default deploy footprint is unchanged.


Platform features (governor)

Production feedback folded back into the Memory Governor: one performance fix
and three read-only operator-visibility endpoints. All are additive; the three
ship-dark features leave the daily /digest post byte-for-byte unchanged while
their flags are off.

  1. Contradiction sweep performance hardening. The sweep's candidate query
    (services/memory-governor/src/governor/contradiction.py) is a pg_trgm
    similarity self-join on documents — O(n²) pairs. With no trigram index even
    ~1k eligible docs (~500k pairs) blew through the pool-wide 30s command
    timeout, so every pass raised TimeoutError and no pair was ever judged
    (found in production upstream). Migration
    infrastructure/migrations/0009_contradiction_sweep_perf.sql adds a
    gin (content gin_trgm_ops) index on documents.content, guarded on
    pg_trgm extension presence (managed-Postgres allow-list), with an honest
    built-vs-skipped audit canary. Two new knobs bound the fetch:
    CONTRADICTION_QUERY_TIMEOUT_S (default 300s) is a dedicated timeout for the
    candidate fetch only, and CONTRADICTION_LOOKBACK_DAYS (default 30; <= 0
    disables) bounds steady-state passes to pairs involving a recent doc.
    Regression tests pin the bounds.

  2. Read-only memory inspector summary.
    GET /memory/inspector-summary?workspace_name=… (X-Governor-Key) returns a
    workspace-scoped aggregate for operator inspection: live counts by memory
    class, verification state, and source type (deleted rows excluded); the
    embedding-sync queue depth and last sync; and a 7-day tally of Plane C ranking
    modes (vector / trigram / trigram_fallback). No mutation, no new state
    — same auth as the rest of the /memory/* surface
    (services/memory-governor/src/governor/main.py).

  3. Daily memory review-queue digest (ship-dark). GET /memory-digest
    (services/memory-governor/src/governor/memory_digest.py) is a per-workspace,
    read-only worklist of what needs operator action: pending pin-candidates,
    memories the contradiction sweep flagged needs_review (with the sweep's
    suggested resolution from the review note), and task_scoped memories
    expiring within 7 days. Every section is capped (default 10) with an honest
    "+N more" overflow line, and the raw fetch is bounded (MEMORY_DIGEST_FETCH_CAP)
    so a pathological backlog never loads unbounded rows. Always available for
    preview; MEMORY_DIGEST_ENABLED (seeded off, migration
    infrastructure/migrations/0010_memory_digest_flag.sql) only gates folding the
    listing into the daily /digest post — flag off leaves /digest byte-for-byte
    unchanged.

  4. Escalation SLA auditor (ship-dark). GET /escalation-sla
    (services/memory-governor/src/governor/escalation_sla.py) measures the human
    side of the autonomy handoff. An event taxonomy
    (escalation_opened / escalation_acked / escalation_resolved) on the
    existing agent_events spine, correlated by payload.escalation_id, plus a
    pure pairing/rollup that measures human ack latency against a per-tenant SLA
    (default 30m, optional business-hours clock; malformed config degrades to the
    default with a warning rather than crashing). TTL expiry always counts as a
    breach and as unresolved — the approval gate's fail-closed posture is made
    visible, never weakened. The v1.5 approval seam's autonomy_decision events
    serve as retroactive ack+resolution, so historical holds become auditable the
    moment emitters exist. Read-only throughout: the auditor never approves,
    extends, or re-routes. No new tables — migration
    infrastructure/migrations/0011_escalation_sla_flag.sql is a flag seed only;
    ESCALATION_SLA_ENABLED (seeded off) only gates the /digest fold-in.
    Event emitters land when the HITL approval seam (apps/paperclip/approval.mjs)
    is wired for real volume; until then the pipeline is offline-tested and reports
    an honest zero.

Tests: 205 memory-governor tests (52 new across these four features);
CI green on PRs #100, #101, #102.


Security

  1. Security remediation batch (PR #97). A batch of ~27 findings (aaf-0001
    through aaf-0027) remediated across the auth-proxy, the multi-tenant reference
    design, model-router, chat bridges, memory-governor, the installer /
    forge-console, and the infrastructure modules. This is the headline of the
    v1.7 security posture. The batch groups as:

    • Fail-closed auth. model-router, memory-governor, slack-bridge,
      teams-bridge, and the multi-tenant control-plane / memory-store now refuse
      to serve (503) when their auth secret is unconfigured, instead of silently
      running open.
    • Tenant isolation. memory-store derives tenant_id from a verified
      bearer token (never client-supplied path/body); Postgres RLS backstops both
      the control-plane and memory-store tables; the tenant-console vertical
      field is strictly allowlisted + realpath-contained to close a
      path-traversal route.
    • CSRF / DNS-rebinding. auth-proxy, installer, and tenant-console treat a
      missing Origin as a failed check on state-changing requests, and add
      TrustedHostMiddleware to the loopback-only consoles.
    • Prompt-injection fencing. untrusted inbound text (Slack/Teams messages,
      governed-memory content, watchdog-captured agent error text) is wrapped in
      explicit untrusted-data delimiters before it reaches a model or another
      agent's context.
    • Error-detail hardening. model-router and control-plane no longer echo
      raw upstream/DB exception text to callers; memory-governor projects an
      explicit column list instead of SELECT *.
    • Secure-by-default infra. Key Vault and storage-account firewalls default
      to Deny with explicit allowlist variables; Postgres gains audit/TLS server
      parameters; honcho_workspace_name has no default so environments cannot
      silently share a governed-memory workspace; docker-compose.yml pins image
      tags instead of floating :latest.
    • Installer hardening. scaffold CLI params are allowlist-validated before
      becoming argv (argument-smuggling), and the session-token URL is withheld
      from logs when the browser auto-open succeeds.

    Every route touched is either the sanitized public reference design
    (experimental/multi-tenant/, not wired into the runnable stack) or an
    in-repo service/tool. No infrastructure was applied and no secrets are
    included. Offline test evidence: auth-proxy 43/43, installer 83/83,
    slack-bridge 23/23, teams-bridge 21/21, watchdog 75/75, model-router 195/195,
    memory-governor 153/153, tenant-console 9 passed/1 skipped;
    terraform fmt/validate clean; scripts/scan-internal-refs.sh clean.


Governance examples & samples

Three new self-contained packages land in this release cycle as their own PRs.
Each is sanitized (fictional example data, labeled), flags-off by default, and
readable/testable locally with no live Azure subscription.

  1. examples/governed-ui-patterns/ — a port of the Governed-AI pattern
    library: nine themeable UI governance patterns (honesty badge, trust receipt,
    refusal card, approval gate, pricing-policy engine, autonomy panel, sealed
    record, movement log, signed charter), an 11-check conformance linter
    (check.js) with a documented CI-able exit-code contract, a live demo page,
    and a README covering the composition rules. Copy is vendor-neutral. Tests:
    the linter runs clean on the shipped demo page; node --check on all JS.

  2. samples/foundry-chat-proxy/ — the minimal AI Foundry chat backend
    pattern: a Node 24 Flex Consumption Azure Function fronting an AI Foundry chat
    deployment with a grounded persona (a fictional "Fabrikam Plumbing" grounding
    block, labeled), message clamping, and prompt-injection guardrails; Bicep for
    the function app; and a runbook README including the hard-won gotchas (classic
    Y1 Linux has no Node 24 image, so the host never starts; OneDeploy 415 on
    Flex means use config-zip; secrets are named operator gates). Tests:
    node --check; Bicep compiles if the CLI is available (else documented).

  3. examples/governed-transaction-saga/ — a compact (~300-line + tests)
    sanitized distillation of the event-sourced governance core: an append-only
    event log with tenant/correlation/causation IDs and idempotency, a fold/apply
    state machine for a service transaction, complete-at-write receipts, and an
    audit walk that produces a chronological narrative plus a receipt-gap report.
    Pure Python stdlib with a pytest suite; all-new code written for the example,
    fictional scenario, tied in its README to the platform's HITL approval +
    governor features.


Docs & dependencies

  1. README overhaul. The feature overview now folds in the four governor
    features, the security remediation batch, and the three example/sample
    packages; the release badge moves to v1.7; the "what is included today" and
    "what's not finished yet" sections are brought current; and every quickstart
    path is re-verified against the repo tree.

  2. ROADMAP overhaul. The v1.7 shipped section is ...

Read more

v1.4.0

Choose a tag to compare

@mrobinson2 mrobinson2 released this 05 Jul 19:26
d1076ad

Multi-tenancy, a self-hosted topology, and two more surfaces.

  • Multi-tenant tenant console (reference) — playbook-driven onboarding, per-tenant governed memory + budget caps, isolated workspace. Badged reference with a worked field-service pack.
  • Self-hosted-primary topology — run the full stack on a machine you own as the primary site with Azure as a dormant warm standby on one shared managed Postgres; failover is a stateless compute switch. scripts/aaf-site helper + ADR.
  • Vendor-neutral inbound-intake webhook (reference) — inbound intake/lead payload → routed Orchestrator issue, with signature verification and a fenced untrusted-content boundary.
  • Slack bridge — flag-gated slack-bridge service at parity with Discord/Telegram/Teams (signing-secret HMAC, chat.postMessage replies). Off by default.
  • ACA aca-job sandbox provider (scaffold) — injectable, fully unit-tested transport; the one live REST call is marked unverified and aca-job is disabled everywhere (default local) pending a spike.

315 tests pass; scanners + gitleaks clean; full-stack smoke green. See ROADMAP.md for details.

v1.3.0 — Observability & memory interface

Choose a tag to compare

@mrobinson2 mrobinson2 released this 25 Jun 02:25
8f72c95

Four features, flag-gated where they touch runtime:

  • GenAI-semconv observability — per-call OpenTelemetry spans (model/tokens/cost) to App Insights behind OBSERVABILITY_ENABLED, content-redacted; also closes the Anthropic cost-tracking gap (list-price estimate).
  • ACA Sandboxes — execution seam — provider-pluggable sandbox.mjs (contract + local adapter + fail-closed factory), shipped unwired.
  • Turnkey CI/CD setup page — Forge Console page that runs scaffold-cicd.sh preview-first, secrets via env, server-enforced apply gate.
  • Obsidian memory interface — two-way memory ↔ Obsidian vault CLI: export + conflict-safe sync write-back.

See ROADMAP.md. Operator go-live for observability (deploy + flip the flag) is the remaining activation step.

v1.2.0 — Validated end-to-end Azure deploy

Choose a tag to compare

@mrobinson2 mrobinson2 released this 21 Jun 22:58
b62b60f

v1.2 closes the gap from "infrastructure provisioned" to "a running multi-agent stack on Azure" — and proves it with the first fully validated end-to-end deploy from a clean subscription.

🚀 Headline

  • First fully validated end-to-end Azure deployment from a clean subscription — Container Registry, PostgreSQL Flexible Server, Key Vault, Container Apps, and the core services (PaperClip / Hermes / Honcho) all provisioned and Running, smoke-tested. Walkthrough with screenshots in docs/getting-started.md.

Deploy & operate

  • End-to-end deploy automation — a build → seed → plan → gate → apply → smoke pipeline wrapping the destroy-aware approval gate (#10, #14).
  • Server-side image build & push via az acr build — no local Docker needed (#17).
  • Idempotent Key Vault seeding (scripts/seed-keyvault.sh) and post-deploy smoke tests (scripts/smoke-test.sh).
  • Forge Console upgrades — deployment-id now defaults to gpt-4o-mini, and a new container image-tag field writes the per-service tags into terraform.tfvars (no more hand-editing) (#33).

Run it locally

  • One-command full local stack — vendored PaperClip / Honcho / Hermes sources so all 7 images build from a public clone; scripts/local-stack.sh up (or docker compose --profile full up) (#17, #24).

Integrations

  • Microsoft Teams chat surface — the teams-bridge Bot Framework service files inbound Teams messages as Orchestrator issues and replies with Adaptive Cards, gated by teams_enabled at parity with Telegram/Discord (#11).

Reliability & observability

  • Observability module — opt-in Log Analytics alert rules (watchdog findings, secret expiry, run failures) + an Azure Monitor workbook, no app changes (#14).
  • Secret-expiry monitoring — watchdog detector covered by boundary tests (#12).
  • Model-router test hardening — 146 offline tests across auth, rate limiting, per-tier budget/fallback, Foundry registration, and the OpenAI↔Anthropic translation layer (#13).

Security hardening

  • Auth-proxy webhook prompt-injection fence for untrusted webhook content (#27), Skills-UI XSS escaping (#26), and a hardened governor passthrough path with a new unit suite + CI job (#25).

Deploy bug fixes (surfaced & fixed on the first real run)

  • pg_trgm / fuzzystrmatch added to the Postgres azure.extensions allow-list — fixes PaperClip's ActivationFailed migration crash-loop (#30).
  • data.tf Key Vault secret names reconciled + missing generated secrets added, so terraform plan resolves on a fresh deploy (#15, #31).
  • Non-empty seed placeholderaz keyvault secret set rejects "", so unset externals now seed a sentinel; and the model-router treats that sentinel as "unconfigured" so optional tiers fail-soft skip instead of registering broken (#31, #32).

Docs

  • v1.1 → v1.2 documentation sweep, a full Forge Console deployment walkthrough with 8 (PII-redacted) screenshots, and accurate "what's included / what's not finished" sections.

Full changelog: v1.1.0...v1.2.0

v1.1

Choose a tag to compare

@mrobinson2 mrobinson2 released this 14 Jun 22:49

AzureAgentForge v1.1 — the deployment-automation + governance increment.

Shipped in v1.1

  • Forge Console (./forge) — local web GUI installer: preflight checks, Azure config wizard with tfvars preview, local-state handling, and a live-streamed init → validate → plan → apply with typed confirmations and a destroy-aware apply gate.
  • Reference CI/CD deploy pipeline — GitHub Actions, OIDC auth (no stored secrets), with a destroy-aware approval gate that blocks any plan that deletes or replaces a resource. See docs/deploy-pipeline.md.
  • Governance & blast-radius walkthrough — a destructive request traced through every control that refuses it, backed by 14 golden orchestration replay fixtures.
  • Governed-memory architecture reference (docs/design/memory-system.md) — four planes, six classes, computed trust, contradiction detection, and a self-improvement loop (design reference; governor service not bundled).
  • Measured Azure cost figures validated against real bills.
  • README + roadmap refresh, including a PaperClip UI demo.

Coming in v1.2

Image build & push, Key Vault secret seeding, full service deployment automation, post-deploy smoke tests, one-command full local stack, Microsoft Teams integration, and the first fully validated end-to-end Azure deploy from a clean subscription.