0. How to use this doc
Marketing/30_Foothold/CONTEXT.md. Diagrams are Mermaid source in this file's HTML; edit them as text.1. The system map
Every box that exists or will exist, and what talks to what. The one architectural fact that shapes everything: Entrata only accepts calls from the VPS's static IP (5.78.139.104), and that box is outbound-only. So nothing else ever calls Entrata; everything Entrata-bound goes through an outbox the VPS pulls.
flowchart LR
subgraph FRONT["Front doors (renters & residents)"]
SITE["footholdboise.com
Astro · CF Pages"]
ILS["Apartments.com / Zillow
via Entrata ILS syndication"]
NUM["Ownership # + per-property #
Twilio SMS · calls fwd to LAG"]
end
subgraph EDGE["Cloudflare edge (Workers)"]
WAIT["/api/waitlist"]
AGENT["AI leasing agent
Claude · v1 chat, v2 Agents SDK"]
ENG["Recognition + review engines
cron Workers"]
KV[("KV
availability cache")]
OUTBOX[("Entrata outbox
Queues, pull-consumer")]
end
subgraph VPS["VPS 5.78.139.104 — the only IP Entrata sees"]
POLL["Availability poller
12-min, serial gate"]
RELAY["Entrata relay
outbox consumer, deterministic"]
end
subgraph SAAS["Owned SaaS"]
GHL["GoHighLevel
lead store · tags · drips"]
SUPA[("Supabase
agent datastore")]
HW["Handwrytten
mailed cards + gift cards"]
TRE["Tremendous
digital gift cards"]
end
ENT["ENTRATA
Liberty's system of record"]
LAG["Liberty Asset Group
works natively in Entrata"]
FD["FlightDeck
owner analytics"]
SITE --> WAIT --> GHL
SITE --> AGENT
ILS -- "lead email (1 of 6)" --> AGENT
ILS -- "native CoStar feed" --> ENT
NUM --> AGENT
AGENT --> GHL
AGENT -- "reads" --> KV
AGENT -- "state" --> SUPA
AGENT -- "intents" --> OUTBOX
ENG --> HW
ENG --> TRE
ENG -- "asks via Twilio" --> NUM
ENG -- "log notes" --> OUTBOX
POLL -- "getUnitsAvailabilityAndPricing" --> ENT
POLL -- "publish" --> KV
KV -- "/rentals reads" --> SITE
OUTBOX -- "HTTPS pull" --> RELAY
RELAY -- "sendLeads / updateLeads / sendWorkOrders" --> ENT
ENT --- LAG
ENT -- "financials + WOs + leases" --> FD
GHL -- "funnel metrics" --> FD
classDef live fill:#e2efe5,stroke:#1f6b3a,stroke-width:1.5px
classDef built fill:#e6e9f3,stroke:#3a4a86,stroke-width:1.5px
classDef planned fill:#fff,stroke:#7a7264,stroke-dasharray:5 4
classDef ext fill:#f7ede4,stroke:#bb6238,stroke-width:1.5px
class SITE,WAIT,GHL live
class POLL,RELAY built
class AGENT,ENG,KV,OUTBOX,SUPA,HW,TRE,FD,NUM planned
class ENT,ILS,LAG ext
Component inventory
| Component | Runs on | Repo / location | Status | Notes |
|---|---|---|---|---|
| Public site + /rentals | Cloudflare Pages | foothold-web | LIVE | Gated (NPIfoothold) + noindex until launch. /rentals still static; wires to KV in Phase 1. |
| Waitlist → GHL | CF Worker | foothold-web src/pages/api/waitlist.ts | LIVE | Upsert + tags; ?ref=<email> referral capture. Proves the GHL write path. |
| Ops binder | Cloudflare Pages | foothold-ops | LIVE | This site. Push = deploy (~30s). |
| Entrata service (poller + relay) | VPS 5.78.139.104 | /opt/foothold-entrata, systemd | BUILT | Mock mode. Serial gate + rate-limit capture in. Live client stubbed; config.js still maps old username/password vars — wire ENTRATA_API_KEY. |
| Entrata access | — | Agreement + dev portal + API key | BLOCKED | Key on VPS. Full OpenAPI spec captured (/opt/foothold-entrata/entrata-openapi.yaml). Blocker: Liberty's Add-API-User grant (403 code 115 as of 2026-07-28). Subdomain libertyassetgroup (high confidence). |
| KV availability cache | Cloudflare KV | namespace TBD | PLANNED | CF token is Pages-scope only; namespace creation needs dashboard. |
| Entrata outbox | CF Queues (recommended) | TBD | PLANNED | Pull-consumer over HTTPS keeps the VPS outbound-only. Decide transport at build (§13). |
| AI leasing agent | CF Worker → Agents SDK | spec: strategy/10-ai-agents-spec.md | DECIDED | v1 chat, v2 multi-channel. Tools: check_availability, capture_lead, book_tour, start_application. Daily Opus QA cron. |
| Agent datastore | Supabase | not provisioned | DECIDED | Lead-comms §8: tiered freshness. Conversation state, resident facts, recognition ledger. |
| Telephony | Twilio direct | not provisioned | DECIDED | Brand # + per-property 208 #s, A2P 10DLC, STOP handling. GHL stays for bulk drips only. |
| Recognition engine | CF cron Worker | — | DECIDED | Handwrytten (mail + gift) / Tremendous (digital). Touch map locked in lead-comms §4. |
| Review / social-proof engine | CF cron Worker | — | DECIDED | Event-triggered, never sentiment-gated. Smart links Google + Apartments.com. |
| Unit media packages | — | Liberty marketing team | IN PROGRESS | Photography + 2D floor plans requested of Liberty 2026-07-20 (3D later, on turns). |
| Lead magnet + funnel ladder | GHL workflows | lead-magnets/ (Drive) | IN PROGRESS | Guide outlined, not drafted. Tags: foothold-guide-rent, foothold-sms-optin. |
| FlightDeck wiring | Cloudflare | flightdeck-cre | PLANNED | Pulls Entrata financials + engine metrics per property. Phase 5. |
| AI voice | — | — | PARKED | v1 = all calls forward to LAG. Same brain points at voice later (sequencing call, not a liability one). |
2. The constitution (binding rules, every build)
These came out of research, the Entrata agreement, and the EliseAI post-mortem. They are not preferences. A build that violates one is wrong even if it works.
- Only the VPS talks to Entrata. Its static IP is what Entrata allowlists. The box stays outbound-only (no inbound ports); Workers reach it only via the pull-based outbox. One serial gate per the whole account — Entrata forbids concurrent calls.
- The AI never calls the Entrata API. The access application states no AI touches Entrata; integration code is deterministic. The agent emits structured intents; the relay validates and executes them. Gate: before the agent answers prospects from Entrata-derived data (availability), do the Entrata AI-disclosure review — that crosses into their AI/ML rules.
- Every 1:1 touch logs to Entrata (
updateLeadsnote): recognition sends, escalation replies, agent messages, both directions. Liberty sees everything. Only bulk marketing (drips/broadcasts) doesn't log per-contact. - Minimum-info gate: no guest card without first name + one contact method. Until then the conversation lives in our stack only.
- Never state availability or price without a fresh read. Stale cache or API down → "let me confirm that and get right back to you." This is the EliseAI-proof and the reason Liberty fired the last vendor.
- Review asks trigger on events and go to everyone at that event. Sentiment-gating is prohibited (FTC, Google, Apartments.com). Never re-ask within ~12 months of a public review.
- Fair housing: no steering, same facts to everyone, no demographic characterizations, no promises. The move-in-timing priority rule stays written, neutral, and mechanical. HUD treats AI answers as FHA-subject.
- All Entrata dates/times are Mountain Time. Parse as explicit MT; the VPS runs Pacific, and a lazy parse is a one-day error on dates near midnight.
- Handoff line: ownership owns through tour-booked or application-submitted (plus one post-tour feedback text); LAG owns everything after. The agent owns the conversation channel; LAG works from the logged notes — two people never reply to the same renter.
- Secrets live in
/opt/foothold-entrata/.env(600) and Worker secrets. Never in repos, never echoed in logs or error paths, never in this binder.
3. Data topology: four stores, four jobs
Each store owns one kind of truth. When two docs disagree about "where data lives," this table governs.
| Store | Owns (the truth for) | Written by | Read by | Freshness |
|---|---|---|---|---|
| Entrata | Operational record: units, availability, guest cards, leases, work orders, residents | VPS relay only (our side); LAG natively | VPS poller | Source of truth |
| Cloudflare KV | Availability cache the site + agent read | VPS poller | /rentals, agent check_availability | ≤12 min + live re-check at commit |
| GoHighLevel | Marketing: leads, tags, drips, referral attribution | Waitlist Worker, agent capture_lead, GHL workflows | Agent, FlightDeck funnel metrics | Real-time |
| Supabase | Agent state: conversations, resident facts (pets, birthdays, tenure), recognition ledger | Agent, engines, daily VPS pull | Agent, engines | Tiered (lead-comms §8) |
Contracts to pin at build time
| Interface | Proposed shape (finalize in Phase 1–2) |
|---|---|
| KV keys | avail:<propertyId> → {updatedAt, propertyName, units:[{unitId, unitNumber, floorPlan, beds, baths, sqft, rent, availableDate, status}]} + avail:index (property list + last-sync). Mock poller already writes this shape to cache/availability.json. |
| Outbox message | {intent: "logNote"|"sendLead"|"sendWorkOrder", propertyId, payload, dedupeKey, createdAt}. Relay validates against a whitelist of intents — the deterministic boundary of rule 2. |
| VPS env (names only) | MODE, ENTRATA_API_KEY, ENTRATA_DOMAIN, ENTRATA_PROPERTY_IDS, POLL_INTERVAL_MIN, CACHE_DIR, CF_ACCOUNT_ID, CF_KV_NAMESPACE_ID, CF_API_TOKEN, GHL_API_KEY, GHL_LOCATION_ID. (ENTRATA_USERNAME/PASSWORD are legacy from the pre-gateway guess; remove when wiring the key.) |
| GHL tags | foothold-guide-rent (lead magnet), foothold-sms-optin (Insider list), waitlist source tags per foothold-web src/lib/ghl.ts (code is SoT). |
4. The Entrata protocol (applies to every flow below)
Established by live probes + the captured OpenAPI spec (2026-07-28). Spec copies: /opt/foothold-entrata/entrata-openapi.yaml (VPS) and Marketing/30_Foothold/entrata/entrata-openapi-2026-07-28.yaml (Drive). 18 groups, 128 methods, 302 schemas.
| Fact | Detail |
|---|---|
| Base URL | https://apis.entrata.com/ext/orgs/<subdomain>/v1/<group> — subdomain is the client's (libertyassetgroup, pending written confirm), group is the URL, method goes in the body. POST only. |
| Auth | Header X-Api-Key + Content-Type: application/json. Body envelope: {"auth":{"type":"apikey"},"requestId":"n","method":{"name":"...","version":"r1","params":{...}}}. |
| Method → group map (the gotcha) | getUnitsAvailabilityAndPricing, getPropertyUnits, getAmenities, getSpecials → propertyunits. getProperties, getFloorPlans, getPropertyMedia → properties. sendLeads, updateLeads, getLeads, getLeadPickLists → leads. getWorkOrders, sendWorkOrders, updateWorkOrders, getWorkOrderPickLists → maintenance. getLeases, getLeaseDetails, getExpiringLeases → leases. getCustomers → customers. getGlTransactions, getBudgets, getBudgetActuals, getBankAccounts → financial. |
| Discovery | getAccessibleClients on /ext/orgs/rsync/v1/appinfo (literal rsync) returns every org the key can reach: {subdomain, id, name}. First call to run when Liberty's grant lands — confirms subdomain + scope. getProperties then populates ENTRATA_PROPERTY_IDS. Health: getStatus → status. |
| Rate limits | Per-minute / hour / day, per service, returned in every response's headers. No concurrent calls, ever (serial gate). Poll cadence 10–15 min per plan; ~8–12K calls/mo declared in the application. |
| Maintenance windows | Scheduled: Tue late night → Wed early morning MST, weekly. Unscheduled: late evening/early morning Sun/Mon/Wed/Thu. The poller treats downtime as normal: back off, serve last-good cache, no alarms unless stale > 2h. |
| Timezone | Everything MT unless stated. Parse explicit; display MT (Boise is MT). |
| Error vocabulary | 400/1415 missing Content-Type · 400/1404 method not found (wrong group path) · 401/405 client exists, key not permissioned · 403/115 key valid, webservice not enabled · 404/111 no such client · 405/1405 wrong verb. |
5. Flow A — availability pipeline BUILT (mock) BLOCKED (live)
Feeds: /rentals, the agent's check_availability, ILS freshness. KPI: apps-per-tour + vacancy days. The EliseAI failure this design exists to prevent lives here.
sequenceDiagram
autonumber
participant T as VPS timer (12 min)
participant G as Serial gate
participant E as Entrata
participant K as CF KV
participant W as /rentals
participant A as AI agent
T->>G: tick (skip inside maintenance windows)
G->>E: POST /{org}/v1/propertyunits — getUnitsAvailabilityAndPricing (per property)
E-->>G: units + pricing (MT dates) + rate-limit headers
G->>K: publish avail:{propertyId} + avail:index
W->>K: read on page view (never hits Entrata)
A->>K: check_availability tool
Note over A,E: Commit moment (quote / apply link):
one targeted live re-check via the relay — sparingly, it spends rate budget
Note over G,E: Backoff ladder: rate-header low → stretch interval;
5xx/maintenance → serve last-good, alert only if stale > 2h
6. Flow B — lead capture & speed-to-lead PLANNED
KPI 1 (apps per tour). The agent answers in seconds on its own number; Entrata gets the complete mirror. Handoff at tour-booked or application-submitted.
sequenceDiagram autonumber participant P as Prospect participant I as Apartments.com / Zillow participant A as AI agent participant H as GHL participant Q as Outbox participant V as VPS relay participant E as Entrata participant L as Liberty P->>I: inquiry (real name, email, phone, move-in date) I->>E: native CoStar feed → guest card I->>A: lead email (one of 6 destinations) A->>P: reply in seconds, own number, 24/7 Note over A: Min-info gate: first name + one contact method
before anything touches Entrata A->>H: capture_lead + tags + source A->>Q: intent: logNote / sendLead Q->>V: HTTPS pull (outbound-only box) V->>E: getLeads by email — dedupe first alt card exists (ILS path) V->>E: updateLeads — note on existing card else no card (site / chat / SMS lead) V->>E: sendLeads — create guest card end Note over V,E: EVERY message both directions logs as a note.
Notes are record-only — no send API exists, so no duplicate risk. A->>P: book tour or ProspectPortal apply link Note over A,L: ── HANDOFF: tour booked OR application submitted ── L->>E: tour, leasing, move-in — natively A->>P: one post-tour feedback text (~1–2 hrs)
getLeads for an in-progress status gone stale (verify per-property status IDs with one test application), then the agent re-engages. ILS listing freshness rides on Entrata's native syndication (Liberty flips it on; Marketing Hub → ILS Portal) — not our API problem, but our weekly report card grades it.7. Flow C — turn engine DECIDED
KPI 2 (vacancy days → ~0). Ready date = move-in date; the only downtime is the ~3-day make-ready.
flowchart LR N["Notice to vacate
(Entrata: getLeases / getExpiringLeases)"] --> D["Compute available date
vacate + Liberty turn SLA (~3–4 days)"] D --> C["Liberty confirms ready date
(pre-inspection walk; nothing goes out before)"] C --> M["Match waitlist on optional profile
beds / budget / pet / timing"] M --> W1["1. Matched Insiders — 48-hr early window
texted first, ordered by stated timing"] W1 --> W2["2. Broader waitlist"] W2 --> W3["3. Public listing — ILS syndication fires"] W1 -.-> APP["Applications"] W2 -.-> APP W3 -.-> APP APP --> R["Allocation rule (written, neutral, mechanical):
among QUALIFIED applicants, completed app
closest to the ready date wins"] R --> S["Lease signed → move-in = ready date"] classDef lag fill:#f7ede4,stroke:#bb6238 class C lag
8. Flow D — recognition engine DECIDED
KPI 3 (renewal 57% → 70%). Real cards in the mail, zero staff tasks. Touch map + tone rules locked in lead-comms §4.
sequenceDiagram
autonumber
participant V as VPS (daily pull)
participant S as Supabase
participant C as Recognition cron
participant HW as Handwrytten
participant TR as Tremendous
participant T as Twilio (ownership #)
participant Q as Outbox → Entrata
V->>S: resident facts — leases, renewal dates, pets, move-ins (getLeases / getCustomers)
C->>S: read trigger matrix (move-in, birthday, pre-renewal −90d, tenure, life events)
alt mailed touch (welcome / birthday / pre-renewal / tenure / sympathy)
C->>HW: handwritten card (+ $25 gift card where the map says)
else digital gift
C->>TR: gift card by text
end
C->>T: follow-up text the night it lands — "make sure you got your package"
C->>Q: log note — "mailed birthday card + $25 gift card"
Note over Q: PM sees every touch in the Entrata thread (rule 3)
Note over C: Pre-renewal card lands ~90 days out, AHEAD of the ~60-day offer.
Gift-then-offer reads genuine; offer-then-gift reads like a bribe.
9. Flow E — review / social-proof engine DECIDED
KPI 4 (3.9★ → 4.5★+). Event-triggered asks at goodwill peaks; reviews feed ILS rank and the site funnel.
sequenceDiagram autonumber participant E as Entrata events participant S as Supabase participant C as Review cron participant T as Twilio participant R as Resident participant G as Google / Apartments.com E->>S: move-in +2wk · WO completed · renewal (via VPS pulls) S->>C: recognition sends (from the ledger) C->>C: suppression — public review in last ~12 mo? spaced enough? → skip C->>T: the ask, from the ownership number T->>R: text + smart link (or the service-call card, left on site) R->>G: public review G-->>C: monitor → ILS scorecard + site testimonials C->>E: log the ask (outbox note) Note over C,R: Trigger on EVENTS, ask EVERYONE at that event.
Sentiment-gating is prohibited — that's rule 6, not a style choice.
10. Flow F — escalation & edge handling DECIDED
flowchart TD
M["Message on the ownership channel"] --> GD{"Guardrail check
(Haiku pre-pass)"}
GD -- "leasing, in scope" --> RE["Agent replies
logs note via outbox"]
GD -- "service ticket" --> SR["Acknowledge instantly + redirect gently
'Liberty's responsibility, we passed it on'"]
SR --> WO["sendWorkOrders via relay
(emergency → maintenancePriorityId from
getWorkOrderPickLists, mapped per property)"]
WO --> LAG["Liberty resolves — natively, their SLA"]
GD -- "out of its depth" --> ESC["'Let me get a person' + urgent note
on the guest card → Liberty takes over"]
GD -- "agent / API down" --> FB["Fallback email to the Liberty PM
with lead + full context — nothing lost"]
LAG -.-> AGG["Foothold watches the AGGREGATE
(rating trend, review velocity, renewals)
never per-ticket policing"]
classDef crit fill:#f3e0dd,stroke:#9a3b2b
class FB crit
11. FlightDeck & reporting PLANNED
The shared cockpit from the Overview: per-property KPIs, NOI vs budget, DSCR, flags. Sources, per property:
| Board metric | Source |
|---|---|
| Phys/econ occupancy, NOI vs budget, DSCR, delinquency | Entrata financial group (getGlTransactions, getBudgets, getBudgetActuals, getBankAccounts) + artransactions / arpayments, via VPS pulls |
| Apps/tour, speed-to-lead, cost per lease | GHL funnel + Entrata getLeads / getLeadEvents source tagging |
| Renewal rate, vacancy days | Entrata getLeases / getExpiringLeases + turn-engine ledger |
| Rating, review velocity | Review-engine monitor (Google + Apartments.com) |
| ILS grade (weekly report card to Liberty) | Listing-freshness checks + review presence + photo completeness — the scorecard the agent grades weekly |
12. Scope traceability: the Overview's promises → this design
Everything promised on / maps here. If a promise has no flow, the design is incomplete; if a flow serves no promise, cut it.
| Overview promise | KPI target | Flow | Components on the critical path |
|---|---|---|---|
| Demand engine: owned list, 24/7 agent, Insider blast, sight-unseen media | 0.4 → 3.0 apps/tour | B (+ A) | Agent, GHL funnel, Twilio, availability cache, unit media packages, ProspectPortal links |
| Turn engine: pre-leased before empty | ~41 → ~0 vacancy days | C (+ A) | Lease pulls, waitlist matching, Insider 48-hr window, Liberty ready-date confirm |
| Recognition engine: auto-mailed cards + gifts | 57% → 70% renewal | D | Resident-facts pull, recognition cron, Handwrytten, Tremendous, Twilio, Entrata logging |
| Review engine: ask at goodwill peaks | 3.9 → 4.5★+ | E | Event triggers, suppression ledger, smart links, service-call card |
| Econ occupancy (rollup) | ~90% → 95%+ | A–E | All of the above + FlightDeck delinquency/concession visibility |
| Brand-rent premium (the proof) | +5–8% | all | The system working; measured in FlightDeck vs market comps (HelloData) |
| Escalations as clean tickets; full PM visibility | — | F | Guardrails, work-order relay, note logging |
| FlightDeck, one board both sides see | — | §11 | Financial pulls, engine metrics, ILS grade |
13. Build sequence & gates
| Phase | Deliverable | Status | Gate / dependency |
|---|---|---|---|
| 0 | Site, waitlist→GHL, binder, VPS + mock service, Entrata agreement + portal + key + full OpenAPI spec | DONE | — |
| 1 | Availability live: wire ENTRATA_API_KEY into config, live parse (MT dates), KV publish, /rentals reads KV, backoff + maintenance windows. First calls: getAccessibleClients → getProperties → populate property IDs. | BLOCKED | Liberty's Add-API-User grant (asked 2026-07-28; email drafted). Read the Webhooks portal page before wiring. Dev happens against Liberty's training/test company first. |
| 2 | Lead loop: outbox transport (Queues recommended), relay intents, sendLeads/updateLeads with dedupe, CoStar lead-email destination pointed at the agent inbox, ILS syndication flipped on by Liberty | PLANNED | Phase 1 + test-company validation of writes. Liberty flips ILS Portal on. |
| 3 | Agent v1: /api/chat Worker + widget, tools (check_availability on KV, capture_lead, book_tour, start_application), transcripts + daily Opus QA cron, Twilio numbers + A2P | DECIDED | Phase 1 (availability data) + Entrata AI-disclosure review (rule 2) + A2P registration lead time |
| 4 | Recognition + review engines: Supabase provisioned, resident-facts pull, Handwrytten/Tremendous accounts, trigger matrix, suppression ledger | DECIDED | Phase 1 (lease/resident reads on real properties — needs Aspen/Summerset live in Liberty's Entrata post-PMA) |
| 5 | FlightDeck wiring + weekly ILS report card | PLANNED | Phase 1 financial reads; report card can start semi-manual earlier |
| 6 | Voice (same brain, Vapi/Retell-class building block) + applications-push if ever needed | PARKED | Agent proven on chat first — a maturity decision, not a liability one |
| 🏁 | Launch: remove gate + noindex on both sites (gate.js here; Base.astro + robots.txt on foothold-web) | PLANNED | Brent's call |
14. Open questions (decide at the marked phase)
| Question | Phase | Current lean |
|---|---|---|
| Webhooks vs 12-min polling | 1 | Read the portal Webhooks page; if events cover availability + leads, poll becomes a reconciliation pass. Inbound endpoint goes on a Worker, never the VPS. |
| Outbox transport | 2 | CF Queues pull-consumer (HTTPS pull keeps the VPS outbound-only). Alternatives: D1-backed table + tiny Worker API. Current CF token is Pages-scope — either needs a dashboard visit. |
| Subdomain written confirmation | 1 | libertyassetgroup per error-code probes; confirm via getAccessibleClients the day the grant lands. |
| Abandoned-app status IDs | 2 | Run one test application in the test company; record per-property status IDs here. |
| North River onto Entrata | 4 | Moving to LAG/Entrata (2026-07-20) — then all three properties ride this one integration. PMS adapter stays anyway. |
| Resident life-event data source (birthdays, pets) | 4 | Welcome Profile + pet form (our data), not the lease. Liberty call transcripts idea is consent-gated — ask Liberty before touching. |
| Cyber-liability insurance (agreement §3.2 rep) | — | Confirm carried; Brent. |
15. Doc registry & supersessions
| Doc | Owns |
|---|---|
| / (Overview) | Scope + the promises. What "done" means. Update it first, align everything else to it. |
| This page | Build SoT: architecture, contracts, statuses, build order. |
| lead-comms-spec | Comms behavior: channels, sequence, touch map, edge cases, freshness tiers. Still iterating. |
| project-plan | Execution: Gantt to the Aug-31 close, who-owns-what, KPI scorecard, deliverables hub. |
| entrata-integration | Connection points + lead-flow research. Partially superseded: its Access & Cost section predates the executed agreement ($0 Year 1, signed 2026-07-20) and the gateway protocol in §4 here. Trust §4 over it on anything API-mechanical. |
Drive: strategy/10-ai-agents-spec.md | Agent architecture, guardrails, QA loop. |
Drive: CONTEXT.md | Operational state + changelog, cross-project. More current than repo docs when they disagree. |
Project memory: entrata-api-auth-shape.md | The probe-established protocol facts + error vocabulary (Claude Code sessions). |
Changelog
| 2026-07-28 | v1. Drawn from the Overview, lead-comms-spec v3, entrata-integration, CONTEXT.md, ai-agents-spec, and the captured Entrata OpenAPI spec. Statuses as of today: Entrata key on VPS, grant blocked on Liberty, mock poller running. |