How The Local Read Database Works
The Daeda AI Automation Suite keeps a local read database for each connected HubSpot portal (via the @daeda/mcp-pro client).
That database is DuckDB.
It lives on your machine.
The local mirror is not one single data source.
It is made from two different systems:
- Artifact-backed data
- Lightweight plugin-backed data
This distinction is very important.
The Simple Rule
Section titled “The Simple Rule”| Data type | Freshness rule |
|---|---|
| Artifact-backed data | Usually handled automatically for normal reads |
| Lightweight plugin-backed data | Not automatically current; refresh it yourself when current values matter |
Where The Local Data Lives
Section titled “Where The Local Data Lives”Each connected portal gets its own local folder.
| File | Purpose |
|---|---|
hubspot.duckdb | Main writable DuckDB database |
hubspot.replica.duckdb | Published read replica for safe reads |
portal_data.json | Local artifact and plugin sync state |
What Counts As Artifact-Backed Data
Section titled “What Counts As Artifact-Backed Data”Artifact-backed data is the main CRM mirror.
It comes from full exports, stored snapshots, and automated follow-up sync flows.
Artifact-Backed Tables
Section titled “Artifact-Backed Tables”| Kind | Examples |
|---|---|
| CRM object tables | contacts, companies, deals, tickets, custom object tables, and other enabled object tables |
| Shared association table | associations |
| Artifact-backed metadata | association_schema, workflows |
How Artifact-Backed Data Arrives
Section titled “How Artifact-Backed Data Arrives”| Step | What happens |
|---|---|
| 1 | The server decides which artifacts exist for the portal |
| 2 | The client requests the latest artifact inventory |
| 3 | The client downloads missing or changed artifacts |
| 4 | It loads those artifacts into the local DuckDB database |
| 5 | It runs catch-up diff logic and selected-portal watch behaviour |
What Counts As Lightweight Plugin-Backed Data
Section titled “What Counts As Lightweight Plugin-Backed Data”Plugins are small metadata sync jobs.
They populate metadata tables that do not ride on the main artifact flow.
These tables are useful, but they are not treated as live real-time data.
Active Lightweight Plugin Tables
Section titled “Active Lightweight Plugin Tables”| Plugin name | Local table or tables |
|---|---|
property-definitions | property_definitions, property_groups, property_definition_object_state |
pipelines | pipelines, pipeline_stages |
owners | owners |
portal-info | portal_info |
action-type-catalog | action_type_catalog |
workflow-enrollment-triggers | workflow_enrollment_triggers, workflow_event_types |
lists | lists |
sequences | sequences, sequence_steps |
communication-subscriptions | communication_subscription_definitions |
conversation-inboxes | conversation_inboxes, conversation_channels, conversation_channel_accounts |
forms | forms, form_fields |
user-teams-permissions | provisioning_users, provisioning_teams, provisioning_roles |
Disabled Bridge-Backed Plugins
Section titled “Disabled Bridge-Backed Plugins”These plugin names exist in the codebase, but they are currently disabled and not part of the normal active sync surface.
| Disabled plugin | Table |
|---|---|
snippets | snippets |
email-templates | email_templates |
account-settings | account_settings |
record-views | record_views |
Why Plugins Need Manual Refresh
Section titled “Why Plugins Need Manual Refresh”The Automation Suite client does not keep lightweight plugin tables continuously current.
It can auto-skip plugin sync when data looks fresh enough.
The built-in freshness window is 24 hours.
That means plugin tables can be correct enough for many tasks, but still not current enough for operational work.
Which System Should You Trust For Freshness
Section titled “Which System Should You Trust For Freshness”| Need | What to trust |
|---|---|
| CRM records and associations | Artifact-backed local mirror |
| Workflow snapshot plus selected-portal workflow deltas | Artifact-backed workflows table |
| Lists, owners, pipelines, forms, inboxes, sequences, and similar metadata | Plugin freshness in status(section="schema") |
Real-Time And Near-Real-Time Behaviour
Section titled “Real-Time And Near-Real-Time Behaviour”Selected Portal
Section titled “Selected Portal”The selected portal gets the strongest freshness behaviour.
| Data type | Behaviour |
|---|---|
| CRM object records | Catch-up diff plus live watch behaviour |
| Associations | Updated through the same diff/watch path |
| Workflows | Snapshot artifact plus selected-portal workflow delta messages |
| Plugin-backed metadata | Still manual refresh when current values matter |
Non-Selected Enabled Portals
Section titled “Non-Selected Enabled Portals”Non-selected portals do not get the same live behaviour as the selected portal.
Reads can still use the local mirror.
For enabled portals, the client can wait for artifact queue work to drain before reading.
That helps artifact freshness.
It does not make plugin metadata current.
Disabled Portals
Section titled “Disabled Portals”If portal sync is disabled, the Automation Suite only uses stale local data for that portal.
If no local database exists yet, reads fail.
The Main Mental Model
Section titled “The Main Mental Model”Use this model:
| Question | Answer |
|---|---|
Is this table a CRM object table, associations, association_schema, or workflows? | Treat it as artifact-backed |
Is this table owned by a named lightweight plugin such as lists or owners? | Treat it as plugin-backed and manually refresh when needed |
How To Check Freshness
Section titled “How To Check Freshness”Always use:
status(section="schema")This is the authoritative freshness view.
What To Look For In status(section="schema")
Section titled “What To Look For In status(section="schema")”| Field | Meaning |
|---|---|
lightweightPlugins.<plugin>.status | Plugin state such as NOT_STARTED, SYNCED, or FAILED |
lightweightPlugins.<plugin>.lastRefreshedAt | Replica-backed last refresh time |
lightweightPlugins.<plugin>.ageSeconds | Age of that plugin data |
refreshJobs | Active and recent plugin refresh jobs |
When You Must Run refresh_plugins
Section titled “When You Must Run refresh_plugins”Run refresh_plugins before any task that depends on current plugin-backed metadata.
Common Cases
Section titled “Common Cases”| If you need current… | Refresh these plugins first |
|---|---|
| owners | owners |
| deal or ticket pipelines | pipelines |
| lists | lists |
| workflow trigger catalog | workflow-enrollment-triggers |
| supported workflow action metadata | action-type-catalog |
| forms | forms |
| inboxes and channels | conversation-inboxes |
| sequences | sequences |
| communication subscription definitions | communication-subscriptions |
| provisioning users, teams, and roles | user-teams-permissions |
If a task needs several of these, refresh them together in one call.
The Correct Refresh Workflow
Section titled “The Correct Refresh Workflow”| Step | Action |
|---|---|
| 1 | Call status(section="schema") |
| 2 | Decide which plugin-backed metadata you need |
| 3 | Call refresh_plugins(pluginNames=[...]) |
| 4 | Poll status(section="schema") again |
| 5 | Wait until the matching refresh job is COMPLETED |
| 6 | Also confirm the plugin lastRefreshedAt values have advanced |
| 7 | Only then run query, chart, or plan-building work that depends on those tables |
Why COMPLETED Matters
Section titled “Why COMPLETED Matters”COMPLETED does not just mean the remote work finished.
It means the writable client has also published and verified the updated read replica.
That is why status(section="schema") is the real gate.
Refresh Job States
Section titled “Refresh Job States”| State | Meaning |
|---|---|
QUEUED | Job created but not started |
RUNNING | Refresh logic is executing |
REPLICATING | The local read replica is being published and verified |
COMPLETED | Refresh finished and the replica is verified |
FAILED | Refresh failed; use the error message |
Safe Examples
Section titled “Safe Examples”Safe To Query Without Plugin Refresh
Section titled “Safe To Query Without Plugin Refresh”| Question | Why |
|---|---|
Which deals are in closedwon? | CRM object data |
| Which contacts belong to which companies? | CRM object data plus associations |
| How many workflows are enabled? | Artifact-backed workflows table |
Refresh First
Section titled “Refresh First”| Question | Why |
|---|---|
| Which owners exist today? | owners is plugin-backed |
| What are the current deal stage IDs? | pipelines is plugin-backed |
| What is the latest list ID for a static list? | lists is plugin-backed |
| What forms exist right now? | forms is plugin-backed |
A Few Important Nuances
Section titled “A Few Important Nuances”| Nuance | What it means |
|---|---|
workflows is not a plugin table | It is artifact-backed |
property-definitions is a plugin | Refresh it manually when schema freshness matters |
| Read-only MCP clients can still serve reads | They use the published local replica |
| Plugin refresh can be relayed | A read-only client can request refresh through the writable master client |
Recommended Habit
Section titled “Recommended Habit”Use this rule before every serious query:
| If your task depends on… | Do this |
|---|---|
| CRM records only | status(section="schema"), then query |
| CRM records plus plugin metadata | status(section="schema"), then refresh_plugins, then wait for replica-verified completion, then query |