License: This repository is published under the Discouraged Usage License. Use is permitted, but strongly discouraged. See
LICENSEfor full terms.
Standalone experiment suite answering: can an LLM agent navigate a structured brand-rule knowledge graph precisely enough to assign the right ruleset to each email-blueprint section? (Benchmarked later against humans doing the same task; FNR-first.)
Branch
token-first-kb: token-first KB variant. Extraction runs token-level first and exhaustively — every concrete styling value is aprimitivetoken; every element-path binding (which value applies where, under what condition) is asemantictoken whosevalue.variants[].whencarries the IF/ELSE formerly written as prose rules. Rules become coherent topic CLUSTERS that bind tokens instead of restating values; expect token counts >= rule counts. New tools:query_tokens,search_tokens; new graph edges:resolves_to(semantic -> primitive).mainholds the atomic-rule baseline.
shared/registries.json(committed = permanent) holds DYNAMIC vocabularies:section_types(curated core + brand-discovered devices, e.g. ibsrela'ssymptom_trio),relations(enriched with overrides / mutually_exclusive / depends_on),token_types. Extraction proposes novel entries asother.<name>; the build registers real discoveries permanently, bare unknown values are dropped.- Concrete approved templates (
config.TEMPLATE_LIBRARIES, e.g. the ibsrela email header/footer library) are ingested ascontent_sub_typerows withcovers_section_types(a header-with-hero template covers[top_matter, hero]),template_ref/template_file(bodies stored underkb/{brand}/templates/), andcovers_sectiongraph edges. Rules scope to templates/components viacontent_sub_type_ids(null = all email sub-types) — same mechanism dimension formats use for banner-size-specific rules. New tool:rules_for_subtype. - Token hygiene: exact duplicates (same kind+type+value+scope) are auto-merged at build
time (merged names survive as aliases;
$refs remapped); near-duplicates across scopes are reported toreview/token_near_duplicates.md, not merged. Query-time multi-level composition is handled by theresolve_tokentool (flattens$refchains to concrete values with variants). - Asset vocabulary:
wavegeneralized tographic_device(brand-look motifs: waves, swooshes, accent shapes, patterns).
content_sub_type= structural CLASSES only (source-defined component library, locked matter, dimension formats). Role-echo pseudo-components are gone — recurring section patterns stay rules + selector + tokens.- New
design_templateentity (tpl_): concrete approved artifacts from template libraries AND approved MJML blocks embedded verbatim in the bibles. Templates fill section roles (fills_section_types), may realize a class (instance_of), sit in pick-onetemplate_groups (tgr_, e.g. approved email headers), and carry their ownusage_conditions(selection gates likerequires_content_tags: [lpga], inferred automatically when a template's body references a gated asset). covers_section_typessplit intofills_section_types(IS the role; feeds rule surfacing) vshosts_section_types(CAN CARRY the role; affordance hint only).- Rules scope to classes only;
tpl_/tgr_ids incontent_sub_type_idsare rejected at validation. New tools:list_templates,rules_for_template(instance view: rules via class + via filled sections + own usage_conditions + group alternates).
The standalone governance entity is retired. Compliance statements (required
disclosures, mandated qualifiers, verbatim-only messaging, trademark adjudications) are
ordinary brand_rule rows carrying a governance facet:
{gov_type, verdict, preferred_form?, match?, severity} — the exact required strings
live in governance.preferred_form, and such rules land as hard_constraint. They
surface in every normal rule query (no separate corner for the agent to forget) and are
filterable via query_rules(has_governance / gov_type / verdict); keyword_search
indexes the verbatim strings. MLR-specific bookkeeping (evidence, effective_from,
expires_at) was dropped for now.
Inputs: a structured brand-rules KB (migrated from the design bibles) + an email blueprint
(content_blueprint[], with or without per-section design_concept).
Output per section: targeted_rules (precisely scoped to that section) and
email_wide_rules (baseline, union-deduped across sections with vote provenance).
cd rule_navigation
python3.13 -m venv .venv && .venv/bin/pip install -r requirements.txt
# API keys are read from ../.env (OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY or GEMINI_API_KEY)# 0. Migrate design bibles -> structured KB (one-time; LLM outputs cached in indexing/_cache)
.venv/bin/python -m indexing.build_kb --brand lisraya ibsrela
# 1. Rule summaries + embeddings (3 Chroma collections per brand: summary/intent/text)
.venv/bin/python -m indexing.summarize_embed
# 2. Run architectures over a blueprint
.venv/bin/python -m runner.run_blueprint --arch all --brand ibsrela \
--blueprint examples/ibsrela_blueprint.json
# 3. Compare runs
.venv/bin/python -m runner.compare outputs/<run_a> outputs/<run_b> outputs/<run_c>Useful flags on run_blueprint: --design-concept off (blueprint-only navigation),
--sections hero cta (subset), --model (any claude-/gpt- chat model),
--section-concurrency.
| style | mechanics | |
|---|---|---|
arch_a_orchestrator |
generalist orchestrator | one loop, full chat history, ALL tools, terminal finalize_section_ruleset |
arch_b_subagents |
querying-style specialists | orchestrator can only delegate (ask_vector/graph/lexical_specialist), each specialist is a scoped loop reporting candidates+evidence; orchestrator merges, iterates, finalizes |
arch_c_schema_network |
schema-sharded network | fixed parallel fan-out of 4 shard agents (color+typography / imagery+assets / layout+assembly+cta / copy+governance), composer agent merges and finalizes |
arch_d_claude_sdk |
Claude Agent SDK filesystem retriever | Claude Code built-ins (Read/Bash/Glob/Grep) navigate kb/{brand}/ on the local disk (Docker/server session). A/B via `--d-tools fs |
arch_e_claude_sdk |
Claude Agent SDK over original bibles | One whole-blueprint session. Built-ins navigate simple_kb/{brand}/ (verbatim design bible + _index.json). Terminal finalize_blueprint_ruleset assigns passage refs like website.color_scheme_rules[3] to sections + email-wide. Opt-in --arch e (not in --arch all). Does not use the structured KB. |
Architectures A–D share the same task brief, section rendering, finalize contract (validated
ids, targeted/email-wide disjoint), tool repository, and tracing — so differences in output
are architectural, not prompt-shaped. Architecture E keeps the same result envelope and
--design-concept toggle, but its rule ids are original-passage refs rather than atomic
rule_* KB ids.
schema/*.md— agent-facing data-model docs (entities, section vocab, predicate registry)rules/*.json+rules/_index.json— atomicbrand_rulerows (v0.2 dictionary: closed-vocabrule_class,selector.section_types,applies_whenpredicates,constraint_type+typedeffect,scope,hardness, derivedtoken_ids/asset_ids)tokens/ assets/ subtypes/ governance/— side entities with indicesgroups/—rule_groups.json(original pre-atomization blobs),asset_groups.json,relations.jsongraph/graph.json— typed nodes+edges (rule→section/token/asset/governance/group, asset pairings, rule↔rule relations)review/— per-blob original-vs-extracted files + build warnings (human spot-checking)vectors/chroma/— persistent local vector store
Byte-identical copies of the original design bibles (not the structured atomization):
design_bible.json— fromnewest_email_pipeline/brand_rules/design_bible_{brand}_1.json_index.json— catalog of every Markdown passage with stable refs (website.color_scheme_rules[3], …)
Architecture E assigns those passage refs to blueprint sections; result.json hydrates
each ref with the verbatim Markdown text.
filesystem (list_dir, read_file, grep) · schema (describe_entity,
get_section_vocab, get_predicate_registry) · lookup (get_rules short/full,
get_entity) · structured (query_rules facet filters, paginated at 80 rows via
offset/next_offset) · tokens (query_tokens facet
filters, search_tokens BM25 over keys/aliases/paths/values) · keyword (BM25) · vector
(3 collections, metadata filters) · graph (rules_for_section, rules_for_token,
neighbors, related_rules) · terminal finalize_section_ruleset factory.
finalize_section_ruleset enforces an FNR-first coverage check: the payload must
declare section_type_mapping (the agent's vocab mapping for the section), and every
mechanically-derivable candidate — rules whose selector matches the mapping, plus all
null-selector (all-sections) rules — must appear in targeted/email_wide or in an
excluded map with a one-line disqualifier. The call fails listing anything unaccounted,
so silent drops (the dominant false-negative mode observed in vetting) are impossible.
Mapping and exclusions persist to result.json (section_types, excluded_rules).
result.json— sections with targeted rules (+why), aggregated email-wide rules (+voted_by), hydrated rule payloads, usage/cost/latency statstraces/{order}_{section}.jsonl— every LLM turn and tool call (args, result sizes, previews) per section; the artifact for judging navigation behavior and for the benchmark harness latercomparison.json(fromrunner.compare) — per-section rule sets, Jaccard overlap, unique-to-arch picks, email-wide agreement
shared/ config, pydantic schemas, LLM tool-loop client, KB access, tool repo, prompts,
simple_kb (original-bible passages for arch e)
indexing/ build_kb.py (migration), summarize_embed.py, static schema docs, _cache/
kb/ generated KB per brand (checked in, human-reviewable)
simple_kb/ original design bibles per brand (Architecture E)
arch_a_orchestrator/ arch_b_subagents/ arch_c_schema_network/
arch_d_claude_sdk/ arch_e_claude_sdk/
runner/ run_blueprint.py, compare.py
examples/ lisraya_blueprint.json (+ blueprint1–4), ibsrela_blueprint.json
outputs/ run results + traces (gitignored-ish; safe to delete)