mxds The agentic analytics IDE

Native macOS, GPU accelerated, made with Rust.
SQL, Python notebooks, dbt native and a terminal for your agents. CLI and MCP built in.

For Apple silicon Macs, macOS 14 or later.

claude×
codex
zsh
+
Claude Code v2.1.289 Opus 5.5 (1M context) with high effort · Claude Max ~/work/shop-analytics
> Paid search revenue is flat but orders grew. Why? ⏺ Comparing Q2 and Q3 by channel in shop_analytics. ⏺ Bash(mxds db sql --conn shop "select channel, …") ⎿ ran in revenue_by_channel.sql, 6 rows in 1.8 ms channel q2_rev q3_rev Δ Paid Search 598 112 612 340 +2.4% Organic 428 870 488 917 +14.0% Referral 251 377 274 008 +9.0% … +3 rows ⏺ Orders grew faster than revenue. Checking what sold. ⏺ Bash(mxds db sql --conn shop "select sku, count(*) …") ⎿ 412 rows in 3.4 ms sku orders avg_price STARTER-KIT 1 487 40.00 PRO-BUNDLE 611 219.00 … +410 rows ⏺ Bash(mxds db sql --conn shop "select campaign, …") ⎿ 3 rows: brand_aug drove 61% of new paid orders ⏺ Bash(mxds chart build bar channel q3_rev) ⎿ chart opened in Results › Chart ⏺ Paid Search orders are up 9.8%, but the average order fell from $136.49 to $127.25. The new brand campaign sells mostly the $40 starter kit, so volume grew while revenue per order dropped. ⏺ Write(q3_report.md) ⎿ Wrote 48 lines, opened in the editor ✻ Checking starter-kit reorders… (14s, esc to interrupt)
Claude Code v2.1.289 Opus 5.5 (1M context) with high effort · Claude Max ~/work/shop-analytics
> Take the starter kit out of fct_revenue and add a first-order flag, then rebuild. ⏺ Search(pattern: "starter_kit", path: "models") ⎿ Found 2 files ⏺ Read(models/marts/fct_revenue.sql) ⎿ Read 42 lines ⏺ Read(models/staging/stg_orders.sql) ⎿ Read 27 lines ⏺ Update(models/marts/fct_revenue.sql) ⎿ Updated with 4 additions and 1 removal ⏺ Update(models/staging/stg_orders.sql) ⎿ Updated with 3 additions and 1 removal ⏺ Bash(dbt build --select stg_orders+) ⎿ Completed successfully, 4 of 4 OK in 6.2s ⏺ Bash(mxds db sql --conn shop "select channel, …") ⎿ 6 rows in 2.0 ms ⏺ Both models rebuilt. Without the starter kit, Paid Search averages $141.06 per order, above Q2's $136.49. ✻ Updating q3_report.md… (9s, esc to interrupt)
Claude Code v2.1.289 Opus 5.5 (1M context) with high effort · Claude Max ~/work/shop-analytics
… 41 earlier messages > Take the starter kit out of fct_revenue and add a first-order flag, then rebuild. ⏺ Update(models/marts/fct_revenue.sql) ⎿ Updated with 4 additions and 1 removal ⏺ Bash(dbt build --select stg_orders+) ⎿ Completed successfully, 4 of 4 OK in 6.2s ⏺ Both models rebuilt. Without the starter kit, Paid Search averages $141.06 per order, above Q2's $136.49. > save context to mxds ⏺ Bash(mxds recall search "paid search aov") ⎿ 1 related note: orders.revenue is net of refunds ⏺ Bash(mxds recall save "Q3 revenue: paid search AOV drop" --tag finding --tag revenue -) ⎿ saved, 6 chunks ⏺ Saved to Recall: the AOV drop and its cause, the starter-kit exclusion in fct_revenue, and the 90-day measure we agreed on. Next session I search there before touching the schema.
Split the starter kit out and rerun without it.
escComment
high · /effort
❯
query_1.sql
revenue_by_channel.sql×
q3_report.md
fct_revenue.sql
+
Run ⌘↩
Explain
Format
Dshop_analytics
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-- Revenue by acquisition channel, Q3 2026
select
    channel,
    count(*)                         as orders,
    round(sum(revenue), 0)           as revenue,
    round(avg(revenue), 2)           as avg_order,
    round(
        100.0 * sum(revenue)
            / sum(sum(revenue)) over (),
        1
    )                                as share_pct
from analytics.orders
where order_date >= date '2026-07-01'
group by channel
order by revenue desc;
Table
Chart
Log
Problems
1 - 6
main3 files +55 −2FetchPull×
Commit message…Commit
Mmodels/marts/fct_revenue.sql+4−1OpenDiscard
@@ -12,6 +12,9 @@Revert
1212select
1313 o.order_id,
1414 o.channel,
15- o.revenue,
15+ o.revenue - coalesce(k.kit_revenue, 0) as revenue,
16+ o.order_seq = 1 as is_first_order
1617from {{ ref('stg_orders') }} o
18+left join {{ ref('starter_kit_lines') }} k
19+ using (order_id)
1720where o.status = 'paid'
Mmodels/staging/stg_orders.sql+3−1OpenDiscard
@@ -4,5 +4,7 @@Revert
44select
55 order_id,
6- channel,
6+ lower(channel) as channel,
7+ row_number() over (partition by customer_id
8+ order by created_at) as order_seq,
79 revenue,
Aq3_report.md+48OpenDiscard
Preview ⌘↩
dbt build
Explain
Format
Compiled100
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
{{
  config(
    materialized='incremental',
    unique_key='order_id'
  )
}}

with orders as (
    select * from {{ ref('stg_orders') }}
),
kits as (
    select * from {{ ref('starter_kit_lines') }}
)

select
    o.order_id,
    o.channel,
    o.revenue - coalesce(k.kit_revenue, 0) as revenue,
    o.order_seq = 1 as is_first_order
from orders o left join kits k using (order_id)
{% if is_incremental() %}
where o.updated_at > (select max(updated_at) from {{ this }})
{% endif %}
Table
Chart
Log
Lineage
Problems
$ dbt build --select fct_revenue+ --target dev Running with dbt=1.11.6 Registered adapter: duckdb=1.10.1 Found 24 models, 3 sources, 31 data tests, 2 exposures Concurrency: 8 threads (target='dev') 1 of 5 START sql incremental model analytics.fct_revenue ...... [RUN] 1 of 5 OK created sql incremental model analytics.fct_revenue . [OK in 0.21s] 2 of 5 PASS not_null_fct_revenue_order_id ..................... [PASS in 0.04s] 3 of 5 PASS unique_fct_revenue_order_id ....................... [PASS in 0.03s] 4 of 5 OK created sql table model analytics.rpt_channel_weekly [OK in 0.09s] 5 of 5 PASS not_null_rpt_channel_weekly_week .................. [PASS in 0.02s] Finished running 2 models, 3 data tests in 0.41s. Done. PASS=5 WARN=0 ERROR=0 SKIP=0 TOTAL=5
Preview
Send 2 comments ⌘⇧↩

Q3 2026 revenue review

claude code, from shop_analytics, 4 Oct 2026

Q3 revenue reached $1.95M, up 4.3% on Q2. Growth came from Organic and Affiliate; Paid Search kept its volume but earned less per order.

revenue_by_channel.png, Q2 vs Q3

Revenue by channel

channelQ2Q3change
Paid Search598 112612 340+2.4%
Organic428 870488 917+14.0%
Email312 405301 552−3.5%
Referral251 377274 008+9.0%
Social205 960196 480−4.6%
Affiliate61 04474 236+21.6%

What changed in Paid Search

The brand campaign launched on 4 August and drove 61% of new paid orders. Its landing page features the $40 starter kit, so the average order fell from $136.49 to $127.25.

Is the campaign the only driver? Check by SKU before we cut the budget.
escComment
  • Orders +9.8%, revenue per order −6.8%
  • Starter-kit buyers reorder within 60 days at 23%
  • Japan is the fastest-growing market, +31% since July
Recommendation: keep the campaign, and measure it on 90-day revenue instead of first order value.
5h 32% 7d 18% 7d 47% Agent ~/work/shop-analytics main 6 rows x 5 cols · 1.80 ms Ln 15, Col 1
Keep computer awakeAgent · Active
OnKeep this computer awake continuously
For − 60 min +Then back to normal sleep
AgentStay awake while an agent is working
OffAllow normal system sleep behaviour
Claude 5h resets in 2h 14m, 7d resets Thu 09:00
Codex 7d resets Mon 14:30

SQL against everything you query

DuckDB, PostgreSQL, Redshift, BigQuery, SQLite and MySQL from one editor with schema-aware completion. Your agent runs the same queries through the mxds CLI or MCP, right in your tab.

Results for you and your agent

You get histograms, null counts and data bars. After every run your agent reads the same result back as token-optimized text, not a wall of JSON.

dbt native

Open a model and press Preview: mxds renders the Jinja and runs it on your profile's target. Run dbt build from the same bar and read the log under the editor, with lineage one tab over.

Every connection, one tree

Warehouses, local DuckDB files and SQLite side by side, grouped your way. Passwords stay in the macOS Keychain.

Run any agent you like

Claude Code, Codex, opencode or the next one: any CLI agent runs in the built-in terminal, in tabs or splits. mxds shows which one is working, idle or waiting for you.

Limits and caffeine, built in

See how much of your Claude and Codex plans is left, and when it resets. Set caffeine to Agent and your Mac stays awake for as long as an agent is working.

Review what the agent wrote

Select a line in the agent's Markdown report or in its terminal output, leave a note, then send every note back in one keystroke.

Watch the edits land

The git view follows your working tree live. Read each hunk the moment the agent writes it, revert the one you don't want, and commit the rest.

Memory that outlives the chat

Recall is a local vector database with local embeddings, one per project. Ask your agent "remember the churn metric we built in August?" and it finds the context, months later.

See how you work

Your usage dashboard: queries by you and by your agents, busy hours, top connections, error rate and agent working time. It is read from a local database on your Mac.

Your agent drives the whole app

With the mxds CLI or MCP, your agent opens tabs, runs queries, builds charts and edits notebooks while you watch, and reads every answer as token-optimized AXI output.

Light and fast.

mxds is native Rust on a GPU renderer. No Electron and no browser engine drawing the interface, nothing between your keystroke and the frame.

120fps

Drawn through Metal, tuned for ProMotion displays.

0.5s*

From launch to a window you can work in. VS Code takes 0.9 s, DataSpell 3.5 s.

183MB**

Memory right after launch, with a project and a terminal open. VS Code uses 870 MB, DataSpell 1.4 GB.

How we measured

Measured in October 2026 on a MacBook Pro with M3 Max, macOS 26. Each app opened the same small folder (a git repository with five .sql files) from a fresh profile, with no extensions or plugins. Launches were warm, with the app already in the disk cache.

* Time from starting the process to the last change of the window contents, read from screen captures every 15 ms.

** Physical footprint summed over every process of the app, about 10 seconds after the window appeared. Memory grows as you work: query results, open tabs, notebook kernels and agent sessions all add to it, so expect more than this over a working day.

To work all day.

Jupyter notebooks, natively

Open any .ipynb on a real kernel. %%sql cells run on your saved connections and hand the result to Python.

[3]
%%sql shop_analytics select country, sum(revenue) as rev from analytics.orders group by 1
countryrev
US742 118
DE388 405
JP301 990

dbt lineage

Your project as a graph, built from the files. Click a model to read its docs, drag boxes to tidy up, export to PNG.

raw.orders raw.items raw.customers stg_orders stg_items stg_customers fct_revenue dim_customers q3_dashboard

15 chart types from any result

Line, bar, heatmap, funnel, waterfall and more, straight from the table you just ran.

Linex weeky revenuecolor channel
0K20K40K60K JulAugSep Aug 10Paid Search 52.0K Paid SearchOrganic

Every query, kept

Yours and your agent's, searchable by text or by the table it touched. Favorites never expire.

select channel, count(*) as orders …mcp, 2m
select * from analytics.orders where …you, 9m
with cohorts as (select customer_id, …you, 1h

Talks to the databases you already have

BigQuery Redshift PostgreSQL MySQL DuckDB and more

Every supported database is listed in the FAQ

The only tool you need.

Download for Mac

For Apple silicon Macs, macOS 14 or later.