- brand_icon_catalog: shared resolver for non-OCI vendor assets (Slack, Jira, Jira Service Management) under kb/diagram/brand-icons; official > fallback; never hits the network at render time.
- oci_diagram_gen + oci_pptx_diagram_gen: services and external actors accept `brand_icon:`, unlocking real multicloud / SaaS topologies beyond Oracle stencils.
- build_bom_comparison_deck: customer-facing Oracle FY26 deck that compares N BOM specs with native PowerPoint charts and live SKU pricing.
- README + SKILL.md: document the new capabilities and ship copy/paste demo prompts (native .pptx diagram, Slack→OIC→Jira flow, multicloud Postgres↔ADB-S, discount-aware BOM).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Six fixes after a Codex transcript that scraped oracle.com for SKUs already
in kb/pricing/oci-sku-catalog.yaml. New option-4 cost-estimate flow with a
"catalog first, web never" rule, staleness gate, and miss policy; unconditional
Cookbook scope (any pricing or SKU work, not just specific tool calls); hard
no-WebSearch rule under "What You Do NOT Do"; disclaimer field extended with
reference-only / no-client-discount clauses and referenced from options 4/8/13
(single source of truth — oci_bom_gen.py already consumes it); tightened menu
hints separating option 4 (quick comparison while you scope) from option 13
(formal .xlsx artefact you send); structural deck verification step for
Linux/WSL where PowerPoint binary isn't available.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause observed in a real Codex session: the agent burned ~3min
on `make venv` + 4 sequential `make diagram-lookup` queries trying
to find a non-existent ref-arch (OCI PostgreSQL accessed FROM GCP
via Cross-Cloud Interconnect). The catalog has 123 entries; if two
honest queries can't surface a topology, none exists — but nothing
in the skill said "stop." Three coordinated fixes:
1) Makefile: `make venv` is now idempotent.
Marker file `.venv/.deps-installed` keyed off `requirements.txt`
mtime — the second `make venv` in a row is a 26ms no-op (was
1m53s on a Codex sandbox, paid every turn). Force a rebuild with
`rm .venv/.deps-installed`.
2) kb/architecture-center/catalog.yaml: new `known_gaps` block.
Surfaced by the lookup tool as a top-of-output banner whenever
the (synonym-expanded) query tokens match any one of a gap's
`triggers` token sets. Two gaps seeded from real engagements:
- gcp-to-oci-native-services — OCI PostgreSQL/OKE/Cache/etc.
reached FROM GCP via Cross-Cloud Interconnect (the
Database@Google Cloud entries are the OPPOSITE direction).
- newer-oci-services-without-icon — OCI Cache (Redis/Valkey)
and OCI PostgreSQL post-v24.2-toolkit; no ref-arch, no
toolkit icon, fall back to generic stencil + explicit label.
Each gap's `notice:` is a copy-paste recommended composition so
the agent doesn't have to invent a strategy.
3) tools/archcenter_pattern_lookup.py: detects + surfaces gaps.
`lookup()` now returns `{"matches": ..., "gaps": ...}`. The
text printer emits a "⚠ KNOWN GAP — <id>" banner with the
notice block ABOVE the score-based top-K, so the agent sees
the stop-and-compose signal before ever scrolling to results.
YAML output mode mirrors the same shape under `gaps:`.
4) SKILL.md (option 2 step 1) + Codex copy via sync-skill.
New explicit rule: "Lookup budget: max 2 queries — never loop."
Documents the gap banner, the closest-3-then-ask fallback, and
the prohibition against grasping at a 3rd refinement.
Verified manually:
- GCP+postgresql query → gap fires
- "redis ha multi-az" → newer-OCI gap fires
- "exadata cross region data guard" → no false-positive gap
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diego pointed at examples/output-ashburn-redis-oke and asked: does
Oracle ship a Redis icon for drawio? Answer: NO. Confirmed against
both libraries:
- kb/diagram/oci-icons.json (OCI Toolkit v24.2) → 0 hits
- kb/diagram/oci-pptx-icons-index.json (OCI_Icons.pptx) → 0 hits
Same for OCI Cache, Valkey, OCI PostgreSQL — all are GA after the
toolkit shipped.
Oracle's own reference architecture
``modernize-app-dev-oci-postgresql-redis-opensearch`` works around
this by embedding inline SVG vector data into ``shape=stencil(...)``
cells — there is no reusable named stencil. The closest reusable
match is the generic ``database`` icon (8 cells in oci-icons.json,
the canonical "Database" stencil).
Persistent fixes:
- TYPE_TO_ICON (PPTX) and ICON_TYPE_ALIASES (drawio) both gain
aliases for ``redis`` / ``oci_cache`` / ``oci_cache_with_redis`` /
``cache`` / ``valkey`` / ``postgresql`` / ``postgres`` /
``oci_postgresql`` → ``database``. Plus ``opensearch`` →
``database_opensearch`` (which exists) on the PPTX side.
- SKILL.md option 2 step 3 documents the convention: when an OCI
service doesn't have a toolkit icon, use the generic stencil and
pair with an explicit ``label:`` carrying the real service name
(e.g. ``label: "OCI Cache (Redis)"``). When Oracle ships a v25+
toolkit with these icons, update oci-icons.json + the alias tables
and the next render picks up the real icon automatically.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the procedural hole that kept making Codex sessions fall back
to ``examples/`` for YAML scaffolding even after the SKILL forbade it.
The lookup tool returns a canonical Oracle ``.drawio`` as the geometry
source, but the agent had no YAML version of that geometry to copy —
the .drawio is XML with stencil-encoded icons. Without a scaffold,
agents reverse-engineered or fell back to ``examples/`` (which is
forbidden but happened anyway because the alternative was painful).
New tool ``tools/archcenter_drawio_to_template.py`` extracts:
• canvas dimensions
• containers (region / vcn / ad / subnet) classified by stroke /
fill style markers
• service bounding boxes with ``type: TODO_identify`` (the icon
type is encoded in stencil bytes — agent fills it from the
renderer's TYPE_TO_ICON aliases when authoring the spec)
• edge waypoints (source, target, points)
Output lands at ``kb/diagram/assets/archcenter-refs/<slug>/_template.yaml``
next to the .drawio. Lookup now surfaces it as
``cached: yaml=<path>`` so the agent has a one-step "copy this YAML
and adapt" path.
Ran across all 132 cached folders: 107 templates emitted, 24 had no
.drawio (zip didn't ship one), 1 already cached.
Other persistent guardrails added in this commit:
- SKILL.md option 2 step 3: explicit reminder that valid ``type:``
values come from ``TYPE_TO_ICON`` / ``ICON_TYPE_ALIASES`` in the
renderer source plus the icon-index JSON files. Do NOT grep
``examples/`` for ``type:`` — that's where the previous Codex
session was looking, against the rule.
- ``make archcenter-templates-refresh`` Makefile target.
- The lookup index now also indexes ``_template.yaml`` per slug.
- Auto-extracted templates committed under
``kb/diagram/assets/archcenter-refs/*/_template.yaml`` so a fresh
clone has them on first lookup (no extraction step needed).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diego flagged two patterns from the Codex session:
1. Aliases for natural-language slugs were missing — Codex authored
``type: refreshable_clone`` and ``type: oci_goldengate`` and the
resolver returned None for both. Beyond fixing those two, expand
the table proactively: 50+ slugs an SA / agent might naturally
reach for (atp, alb, nlb, apigw, lambda, kms, secret, kafka,
alarm, email, identity, iam, iac, terraform, oac, oic, language /
speech / vision, rpc / lpg / cpe, health_check, tags, etc.) all
mapped to canonical icon entries that exist in
kb/diagram/oci-pptx-icons-index.json.
2. Codex was editing tools/oci_deck_gen.py and the deck-spec while
fulfilling a menu-driven option-2 request — going off the
procedure to "fix" perceived bugs in the renderer. New rule in
SKILL.md § What You Do NOT Do: when the user is in menu mode
(options 1–14), the agent USES the existing tools, never modifies
them. Tool gaps (missing aliases, broken paths) get surfaced as
end-of-reply follow-ups for a separate developer-mode session.
Two narrow exceptions kept: kb/field-findings/tracker.yaml via
option 11, and writing customer spec/output YAML under examples/.
Codex copy auto-synced via the pre-commit hook.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diego flagged that Codex, when authoring an absolute_layout, fell
back to grepping ``examples/`` for AWS/OCI multicloud patterns even
though the procedure said not to. The reason was real: the lookup
tool returns a cached ``.drawio`` (canonical Oracle geometry) but
no canonical ``absolute_layout.yaml`` template, so the agent had no
YAML scaffold to copy the spec shape from.
Tighten the rule rather than ban it outright:
• Cached ``.drawio`` = GEOMETRY source. Container nesting,
padding, AD/subnet placement, icon choices come from there.
• ``examples/`` = YAML scaffold reference ONLY (which fields
exist, how connections are authored, fontSize unit). Do NOT
copy geometry numbers — those came from a different topology.
Rule of thumb baked into the SKILL: if you're copying (x, y, w, h)
from examples/, stop and copy from the cached .drawio instead.
(Codex copy auto-synced via the pre-commit hook installed earlier.)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three-layer defense to keep root SKILL.md (Claude Code) and
.agents/skills/oci-deal-accelerator/SKILL.md (Codex) byte-aligned.
Without this, Claude Code and Codex can drift and give the user
contradictory instructions — exactly the failure mode that produced
the workload-driven-mode incident on 2026-04-25.
Layers (least → most enforcement):
1. Local pre-commit hook (.githooks/pre-commit, opt-in via
``make install-hooks`` which sets core.hooksPath). When SKILL.md
is staged, auto-runs scripts/sync-skill.py and stages the
regenerated .agents/ copy in the same commit. Idempotent.
2. ``make install-hooks`` target + a tip line in ``make venv``'s
output so any new clone discovers the hook setup.
3. CI gate (.gitea/workflows/skill-sync.yaml) on every push/PR
touching SKILL.md or the .agents/ copy. Runs
``scripts/sync-skill.py --check`` and fails the build on drift.
Catches anyone who skipped the hook.
README documents the rationale and the three layers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Codex session showed why the workload-driven mode is the wrong
default. Codex authored a spec under
``tenancy → regions → compartments → services`` (the documented
"workload-driven" mode), generated two .drawio files, and reported
success. The output was unusable: services rendered as colored
rectangles with text instead of OCI icon stencils, connector text
went into the edge value (forbidden by the connector-label rule),
and the spec validator never ran because it only fires on
``absolute_layout`` blocks.
Diego: "los drawio son horribles, por que sucede eso?".
Three persistent fixes:
1. SKILL.md option 2 now says ``absolute_layout`` is REQUIRED for
step 3, calls out workload-driven explicitly as forbidden, and
explains *why* (no stencils, no validator).
2. docs/skill/output-formats.md § Diagram modes is rewritten — mode
1 is ``absolute_layout`` (REQUIRED), mode 2 is workload-driven
(DEPRECATED, back-compat only). Removes the "two acceptable
shapes" framing that let Codex pick the wrong one.
3. ``oci_diagram_gen.py`` now prints a loud stderr WARNING when a
spec takes the workload-driven path, naming the procedure docs.
Catches any agent that skipped reading SKILL.md before generating.
Codex copy synced via ``make sync-skill``.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A Codex session showed the gap: option 2's prose asked the user to
describe the architecture but only mentioned the output formats in
passing ("if you want X / if you want Y"), so the agent never asked
which format(s). Codex also skipped the reference-architecture lookup
and went straight to grepping ``examples/`` for pre-existing specs —
``examples/`` is previous user output, not the authoritative Oracle
catalog.
Two persistent fixes for any agent (Claude Code, Codex, Cursor, …):
1. Option 2 now asks two explicit questions in one message and waits
for both answers before doing anything: (1) describe / paste spec,
(2) pick output format(s) — drawio, native PPTX, or both.
2. The procedure is restated as a numbered list directly under
option 2 (no longer a single-sentence reference to
docs/skill/output-formats.md). Step 1 explicitly says use
``archcenter_pattern_lookup.py`` against the catalog and explicitly
forbids using ``examples/`` as a reference source.
Synced to the Codex copy at .agents/skills/oci-deal-accelerator/SKILL.md
via ``make sync-skill`` so both agents see the same instructions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codex users hit `python: command not found` on the welcome-flow
pre-flight because SKILL.md called `python tools/kb_freshness.py`
directly. Any hardcoded version (python/python3/python3.12) breaks
for somebody — users have 3.8, 3.10, 3.11, 3.12 in the wild.
Fix: channel all skill-initiated Python calls through `make` targets
so the Makefile's single $(PYTHON) variable (auto-detected venv >
3.12 > 3.11 > 3.10 > python3) is the only place Python resolution
lives.
- Makefile: add `kb-check` target emitting JSON for the skill pre-flight
- SKILL.md + .agents/skills/.../SKILL.md: call `make kb-check` and
`make freshness-refresh` instead of bare `python tools/...`
- CLAUDE.md: same fix in the Welcome Flow instructions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Why this set of changes:
- KB pricing was drifting silently — domain files (database.yaml,
storage.yaml, etc.) had prices 30-800% off the live Oracle API and
nobody read them. The skill was auditing as stale on every check
with no path to fix it.
- The skill itself violated Anthropic's spec (`name` field had
uppercase/spaces) and was over the 500-line guideline (647 lines),
hurting discovery and load performance.
- Welcome flow occasionally improvised the menu instead of reading
SKILL.md, missing options.
Pricing — single source of truth, fully automated:
- Extend tools/refresh_sku_catalog.py with --refresh-domain compute,
pulls shape-level prices from the Oracle public pricing API
(apexapps.oracle.com), preserves manual fields (notes, GPU specs,
free-tier annotations, estimation_helpers), recomputes derived
monthly values, and protects $0 free-tier prices from overwrite.
- Delete 12 redundant pricing/<domain>.yaml files. They duplicated
oci-sku-catalog.yaml with worse abstractions and were nobody's
source of truth (no tool consumed them).
- Migrate the genuinely valuable knowledge from those 12 files
(billing models, BYOL rules, free-tier rules, ECPU vs OCPU,
X11M elastic model, hyperscaler comparisons, service nuances)
into kb/field-knowledge/pricing-knowledge.yaml — non-numeric,
no refresh needed.
- Result: pricing freshness check goes from 13 stale files to 0.
KB freshness automation:
- Add tools/kb_freshness.py — wrapper around kb_linter.check_freshness()
with --check, --auto-refresh, --json, --quiet modes. Bridges stale
files to their refresh tools (SKU catalog, compute domain, arch
center). Wired into the welcome flow as a pre-flight banner that
asks the user before refreshing.
- Fix pre-existing kb_linter bug: it crashed on the 45 multi-doc
YAML files (frontmatter + body pattern) because it used safe_load
instead of safe_load_all. Freshness check was effectively dead.
- Standardize timestamp field: linter now accepts last_verified,
last_updated, and last_refreshed; refresh_arch_catalog writes
last_verified instead of last_refreshed.
- Add make freshness / make freshness-refresh targets.
Skill alignment with Anthropic Agent Skills best practices:
- Rename `name: OCI Deal Accelerator` to `oci-deal-accelerator`
to comply with the [a-z0-9-]{1,64} spec.
- Refactor SKILL.md from 674 to 445 lines via progressive disclosure:
extract WA review output format, ECAL readiness format, and output
conventions into docs/skill/*.md referenced from the main file.
- Add scripts/sync-skill.py + make sync-skill: source of truth is
root SKILL.md, .agents/skills/oci-deal-accelerator/SKILL.md is
auto-generated. make lint validates sync.
- Add evaluations/ with 3 manual baseline scenarios (welcome-flow,
full-proposal, wa-review) per the Anthropic best-practices guidance
to "build evaluations first."
Welcome flow hardening:
- Tighten CLAUDE.md to MANDATE reading SKILL.md before showing the
menu (no improvising), and document the freshness pre-flight check
with the ask-before-refresh user flow.
- Update SKILL.md welcome flow to instruct: parse kb_freshness JSON,
show banner with stale count + oldest file, prompt user to refresh
(only when an automated tool exists), fall back silently on errors.
Linter hygiene (zero remaining issues):
- Expand config/kb-tags.yaml taxonomy with features, operations,
metrics, limitations sections covering 31 previously-unknown tags
used in field findings (rac, ecpu, refreshable-clone, hnsw, etc.).
- Assign owners for kb/compatibility/, kb/competitive/,
kb/well-architected/ (Diego Cabrera as default until team grows);
kb/pricing/ marked as "Auto-refreshed" since it no longer needs
human ownership.
- kb_linter accepts top-level `date` as fallback for contributor
block; migrate FF-202603-008 from legacy `reported_by` to
contributor block.
- Result: linter goes from 45 issues to 0.
Other:
- Recompute estimation_helpers monthly values in compute.yaml after
the price refresh (they were derived from the old E5/A1 numbers).
- Add kb/README.md — contributor guide (directory map, frontmatter
spec, refresh tooling, review cadence).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- New tools/oci_bom_gen.py: generates .xlsx BOM from YAML spec with
Oracle Redwood styling, Excel formulas, and Oracle disclaimer.
Supports standard BOM (--output) and AppCA import format (--appca)
- New tools/refresh_sku_catalog.py: refreshes SKU catalog prices from
Oracle's public pricing API (apexapps.oracle.com)
- New kb/pricing/oci-sku-catalog.yaml: ~160 OCI SKUs across 14
categories, validated against Oracle API
- New templates/bom-spec.yaml: input spec template for BOM generation
- Add SA TOOLS section to SKILL.md (options 13-14)
- Register BOM generator in oci_output.py