agami-core 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. agami_core-0.3.2/PKG-INFO +185 -0
  2. agami_core-0.3.2/README.md +164 -0
  3. agami_core-0.3.2/pyproject.toml +51 -0
  4. agami_core-0.3.2/setup.cfg +4 -0
  5. agami_core-0.3.2/src/admin.py +1343 -0
  6. agami_core-0.3.2/src/agami_core.egg-info/PKG-INFO +185 -0
  7. agami_core-0.3.2/src/agami_core.egg-info/SOURCES.txt +42 -0
  8. agami_core-0.3.2/src/agami_core.egg-info/dependency_links.txt +1 -0
  9. agami_core-0.3.2/src/agami_core.egg-info/requires.txt +14 -0
  10. agami_core-0.3.2/src/agami_core.egg-info/top_level.txt +20 -0
  11. agami_core-0.3.2/src/agami_paths.py +180 -0
  12. agami_core-0.3.2/src/contracts.py +239 -0
  13. agami_core-0.3.2/src/deploy_preflight.py +116 -0
  14. agami_core-0.3.2/src/execute_sql.py +785 -0
  15. agami_core-0.3.2/src/mcp_harness.py +150 -0
  16. agami_core-0.3.2/src/mcp_http.py +381 -0
  17. agami_core-0.3.2/src/model_deploy.py +136 -0
  18. agami_core-0.3.2/src/model_store.py +449 -0
  19. agami_core-0.3.2/src/oauth_server.py +660 -0
  20. agami_core-0.3.2/src/oidc.py +190 -0
  21. agami_core-0.3.2/src/onboarding.py +174 -0
  22. agami_core-0.3.2/src/oss_adapters.py +84 -0
  23. agami_core-0.3.2/src/passwords.py +42 -0
  24. agami_core-0.3.2/src/ports.py +106 -0
  25. agami_core-0.3.2/src/semantic_model/__init__.py +35 -0
  26. agami_core-0.3.2/src/semantic_model/build.py +655 -0
  27. agami_core-0.3.2/src/semantic_model/cli.py +1242 -0
  28. agami_core-0.3.2/src/semantic_model/curate.py +1006 -0
  29. agami_core-0.3.2/src/semantic_model/derived.py +201 -0
  30. agami_core-0.3.2/src/semantic_model/dialects.py +617 -0
  31. agami_core-0.3.2/src/semantic_model/introspect.py +1113 -0
  32. agami_core-0.3.2/src/semantic_model/loader.py +543 -0
  33. agami_core-0.3.2/src/semantic_model/metadata_sources.py +232 -0
  34. agami_core-0.3.2/src/semantic_model/models.py +708 -0
  35. agami_core-0.3.2/src/semantic_model/org_draft.py +210 -0
  36. agami_core-0.3.2/src/semantic_model/requirements.txt +11 -0
  37. agami_core-0.3.2/src/semantic_model/runtime.py +1311 -0
  38. agami_core-0.3.2/src/semantic_model/snapshot.py +121 -0
  39. agami_core-0.3.2/src/semantic_model/units.py +192 -0
  40. agami_core-0.3.2/src/semantic_model/validator.py +768 -0
  41. agami_core-0.3.2/src/store.py +166 -0
  42. agami_core-0.3.2/src/tools.py +1226 -0
  43. agami_core-0.3.2/src/ui.py +503 -0
  44. agami_core-0.3.2/src/user_store.py +233 -0
@@ -0,0 +1,185 @@
1
+ Metadata-Version: 2.4
2
+ Name: agami-core
3
+ Version: 0.3.2
4
+ Summary: agami-core — governed semantic model, the shared MCP TOOLS harness, and the unified local query executor.
5
+ Author-email: Agami AI <skills@agami.ai>
6
+ License-Expression: LicenseRef-Agami-FUL
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Provides-Extra: model
10
+ Requires-Dist: pydantic<3,>=2; extra == "model"
11
+ Requires-Dist: PyYAML>=6; extra == "model"
12
+ Requires-Dist: sqlglot>=20; extra == "model"
13
+ Provides-Extra: server
14
+ Requires-Dist: mcp>=1.2; extra == "server"
15
+ Requires-Dist: uvicorn>=0.30; extra == "server"
16
+ Requires-Dist: psycopg2-binary>=2.9; extra == "server"
17
+ Requires-Dist: argon2-cffi>=23; extra == "server"
18
+ Requires-Dist: PyJWT>=2.8; extra == "server"
19
+ Requires-Dist: httpx>=0.27; extra == "server"
20
+ Requires-Dist: cryptography>=43; extra == "server"
21
+
22
+ # agami-core (library)
23
+
24
+ The importable core behind agami: the governed **semantic model**, the shared **MCP `TOOLS`
25
+ harness** (stdio entrypoint), and the **unified local query executor** (`execute_sql` + the
26
+ read-only safety pass + unit formatting).
27
+
28
+ One package serves every consumer — the local Claude Code skill, the MCP server, and any
29
+ downstream that imports the same flat module names.
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ pip install -e packages/agami-core # executor + stdio harness (pure-stdlib)
35
+ pip install -e 'packages/agami-core[model]' # + the semantic model (pydantic / sqlglot / pyyaml)
36
+ ```
37
+
38
+ ## Flat module names (an invariant)
39
+
40
+ `semantic_model`, `mcp_harness`, `execute_sql`, `agami_paths` are top-level importable names —
41
+ no `sys.path` manipulation, no parent package — so a consumer's imports resolve unchanged:
42
+
43
+ ```python
44
+ from mcp_harness import TOOLS
45
+ import semantic_model
46
+ import execute_sql
47
+ ```
48
+
49
+ ## Entry points
50
+
51
+ ```bash
52
+ python -m mcp_harness # the stdio MCP server (Claude Desktop)
53
+ python -m execute_sql --sql … # the local query executor
54
+ python -m semantic_model.cli # the semantic-model CLI (driven by the `sm` launcher)
55
+ python -m mcp_http # the networked HTTP MCP server (see below)
56
+ ```
57
+
58
+ ## HTTP server — networked, with auth (`python -m mcp_http`)
59
+
60
+ The `[server]` extra (`pip install -e 'packages/agami-core[server]'`) adds a networked MCP
61
+ transport: the same `TOOLS` surface as the stdio server, but over HTTP with OAuth + a small admin
62
+ console. It's the self-host shape of the hosted product.
63
+
64
+ ```bash
65
+ PUBLIC_BASE_URL=https://your-host \
66
+ AGAMI_SIGNING_SECRET=$(openssl rand -hex 32) \
67
+ AGAMI_DB_URL=postgresql://… \
68
+ AGAMI_ADMIN_USERNAME=you@example.com \
69
+ AGAMI_ADMIN_FIRST_NAME=Alex AGAMI_ADMIN_LAST_NAME=Kim \
70
+ AGAMI_ADMIN_PASSWORD=… \
71
+ AGAMI_ADMIN_PROVIDER=google \
72
+ AGAMI_OIDC_GOOGLE_CLIENT_ID=… AGAMI_OIDC_GOOGLE_CLIENT_SECRET=… \
73
+ python -m mcp_http
74
+ ```
75
+
76
+ The admin is identified by **email** (`AGAMI_ADMIN_USERNAME`). Their sign-in method is whatever you
77
+ configure — **a password and/or a pinned social provider, at least one**: set `AGAMI_ADMIN_PASSWORD`,
78
+ and/or `AGAMI_ADMIN_PROVIDER` (`google` | `microsoft`, which must also have its
79
+ `AGAMI_OIDC_<PROVIDER>_CLIENT_ID/SECRET` set). The admin login then offers the same Google/Microsoft
80
+ option as the MCP login. Register **one** OAuth redirect URI with the provider —
81
+ `{base}/oauth/oidc/callback` — it serves both the connector and the admin flows.
82
+
83
+ ### One host, two entry points
84
+
85
+ A deployment is one host (`PUBLIC_BASE_URL`). Everything lives under it:
86
+
87
+ | URL | Who | What |
88
+ |---|---|---|
89
+ | `{base}/mcp` | a teammate, in Claude | the **only** URL to add as a custom connector — Claude auto-discovers the OAuth endpoints from it |
90
+ | `{base}/admin` | the admin, in a browser | the console to add/enable/disable users |
91
+
92
+ ### Access model — two separate credentials
93
+
94
+ - **Query surface (`/mcp`)** — gated by a **Bearer JWT** from the OAuth flow. **Any** onboarded user
95
+ who signs in can query (that's the product). No token → `401` + `WWW-Authenticate`, which starts
96
+ Claude's OAuth. Admin-ness does **not** gate `/mcp`.
97
+ - **Admin surface (`/admin`)** — gated by a **session cookie** *and* the admin-gate
98
+ (`AGAMI_ADMIN_USERNAME`). The admin signs in with their **pinned** social provider or a password; a
99
+ valid non-admin is refused (and a social identity for the admin email via a *different* provider is
100
+ refused — the pin closes IdP-confusion). An `/mcp` bearer token is useless here (different
101
+ credential). Unset `AGAMI_ADMIN_USERNAME` ⇒ the admin console is disabled entirely.
102
+
103
+ ### Onboarding a teammate
104
+
105
+ The admin adds a teammate by **email + name** (a *pending* user). How they finish setting up follows
106
+ the deployment's **single auth method** — uniform for everyone, set by what you configured:
107
+
108
+ - **OIDC deployment** (a Google/Microsoft client is configured): the teammate just adds `{base}/mcp` to
109
+ Claude and signs in with that provider — the IdP verifies their email and binds the account on first
110
+ login. No link to share.
111
+ - **Password deployment** (no OIDC configured): the admin **copies the teammate's setup link** from the
112
+ Users tab and shares it out-of-band; the teammate opens it and sets their own password. The link is a
113
+ signed, time-boxed token and is single-use (it stops working once the account is set up).
114
+
115
+ The login surfaces show only the configured method (the admin keeps a password **break-glass** fallback
116
+ on `/admin/login`).
117
+
118
+ > **Trust note.** OIDC onboarding binds the account to whoever first proves the teammate's email at the
119
+ > configured IdP — so add a teammate by an email the *right* person controls there. The setup link and
120
+ > the other pre-auth endpoints aren't rate-limited in-process; put them behind your proxy/LB if exposed.
121
+
122
+ ### Activity view
123
+
124
+ The admin console has one read-only **Activity** tab: every MCP tool call, folded into the conversation
125
+ it belongs to — **thread (conversation) ▸ turn (one user question) ▸ call**. Open a conversation and you
126
+ see its whole arc, *not just the queries*: the `list_datasources` / `get_datasource_schema` calls that
127
+ scoped the work sit alongside the `execute_sql`s that answered it (*"User asked what datasources →
128
+ `list_datasources`; user asked revenue by region → `get_datasource_schema`, then `execute_sql` ×2"*). A
129
+ query call shows its SQL, row count, latency, and status; a non-query call shows its tool name. Every
130
+ call carries its **own** datasource, because a conversation — or even a single turn — can span several:
131
+ the user switches datasource mid-session, or asks something that runs one query per datasource. The
132
+ conversation row lists the full set it touched.
133
+
134
+ The split is deliberate: it is **audit-grade for *what* ran** — the server observes every call directly,
135
+ so nothing is dropped — and **best-effort for *how* it's grouped**. The MCP protocol carries neither the
136
+ user's question, a conversation id, nor a turn boundary, so Claude self-reports them on every call: a
137
+ `user_question` (kept verbatim), a `thread_id` (per conversation), and a `correlation_id` (per turn). The
138
+ turn's question is taken from the **first** call in the turn (the model sometimes drifts it on later
139
+ refinements). When Claude doesn't supply the ids, a call simply shows as its own singleton conversation —
140
+ the view degrades, never drops a call. Treat the self-reported grouping as a hint, not a record.
141
+
142
+ > **Free-tier limit.** A turn that produces **no** tool call — Claude answering "let's continue" from
143
+ > context — never reaches the server and so can't appear here; this is an audit of what ran against your
144
+ > data, not a chat transcript.
145
+
146
+ The `tool_calls` log grows one row per call and has **no automatic retention** — it's your local store,
147
+ so prune it on your own schedule if it gets large.
148
+
149
+ ### Model view
150
+
151
+ The **Model** tab (`{base}/admin/model`) is a **read-only** explorer of the semantic model you've
152
+ deployed — the same tree the MCP tools serve, so it can't drift from what Claude actually reads. It's a
153
+ catalog: a browse rail (datasource → subject area → table) and one page at a time —
154
+
155
+ - a **datasource overview** (description, glossary, storage-connection names/types, the subject areas),
156
+ - a **subject-area landing** (its tables, metrics, entities),
157
+ - a **table page** — the schema, with each column's type and description, and flags only where they
158
+ carry signal (**PK / FK / sensitive / unit / enum / caveat**). Trust is shown as a single table-level
159
+ **confidence** badge; **caveats** (the domain gotchas) are elevated to a callout; wide tables collapse
160
+ behind "show all N", and tables that author `column_groups` render those as collapsible sections,
161
+ - a **Relationships** page (when the model has cross-area joins) — the org-level relationships that
162
+ span subject areas, **grouped by area-pair**, so the cross-area topology is readable in one place,
163
+ - a **domain-context** page (your `ORGANIZATION.md`, rendered as safe markdown).
164
+
165
+ It is **read-only by construction** — a single GET endpoint, no write path. Editing the model stays
166
+ conversational in Claude (the in-app editor is a Hosted feature); connection **credentials are never
167
+ rendered** (names and types only). Deploy a change in Claude and it shows up here on the next deploy.
168
+
169
+ ### Local end-to-end test (HTTPS via a tunnel)
170
+
171
+ OAuth and the `Secure` admin cookie need HTTPS, so expose the local server through a tunnel:
172
+
173
+ ```bash
174
+ # terminal 1 — the server
175
+ PUBLIC_BASE_URL=https://<your-subdomain>.trycloudflare.com \
176
+ AGAMI_SIGNING_SECRET=$(openssl rand -hex 32) \
177
+ AGAMI_DB_URL=sqlite:///$PWD/agami.db \
178
+ AGAMI_ADMIN_USERNAME=you@example.com AGAMI_ADMIN_PASSWORD=choose-a-strong-one \
179
+ python -m mcp_http
180
+
181
+ # terminal 2 — the HTTPS tunnel (prints the https URL to use as PUBLIC_BASE_URL)
182
+ cloudflared tunnel --url http://127.0.0.1:8000
183
+ ```
184
+
185
+ Open `{base}/admin`, sign in, add a user — then add `{base}/mcp` as a connector in Claude.
@@ -0,0 +1,164 @@
1
+ # agami-core (library)
2
+
3
+ The importable core behind agami: the governed **semantic model**, the shared **MCP `TOOLS`
4
+ harness** (stdio entrypoint), and the **unified local query executor** (`execute_sql` + the
5
+ read-only safety pass + unit formatting).
6
+
7
+ One package serves every consumer — the local Claude Code skill, the MCP server, and any
8
+ downstream that imports the same flat module names.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ pip install -e packages/agami-core # executor + stdio harness (pure-stdlib)
14
+ pip install -e 'packages/agami-core[model]' # + the semantic model (pydantic / sqlglot / pyyaml)
15
+ ```
16
+
17
+ ## Flat module names (an invariant)
18
+
19
+ `semantic_model`, `mcp_harness`, `execute_sql`, `agami_paths` are top-level importable names —
20
+ no `sys.path` manipulation, no parent package — so a consumer's imports resolve unchanged:
21
+
22
+ ```python
23
+ from mcp_harness import TOOLS
24
+ import semantic_model
25
+ import execute_sql
26
+ ```
27
+
28
+ ## Entry points
29
+
30
+ ```bash
31
+ python -m mcp_harness # the stdio MCP server (Claude Desktop)
32
+ python -m execute_sql --sql … # the local query executor
33
+ python -m semantic_model.cli # the semantic-model CLI (driven by the `sm` launcher)
34
+ python -m mcp_http # the networked HTTP MCP server (see below)
35
+ ```
36
+
37
+ ## HTTP server — networked, with auth (`python -m mcp_http`)
38
+
39
+ The `[server]` extra (`pip install -e 'packages/agami-core[server]'`) adds a networked MCP
40
+ transport: the same `TOOLS` surface as the stdio server, but over HTTP with OAuth + a small admin
41
+ console. It's the self-host shape of the hosted product.
42
+
43
+ ```bash
44
+ PUBLIC_BASE_URL=https://your-host \
45
+ AGAMI_SIGNING_SECRET=$(openssl rand -hex 32) \
46
+ AGAMI_DB_URL=postgresql://… \
47
+ AGAMI_ADMIN_USERNAME=you@example.com \
48
+ AGAMI_ADMIN_FIRST_NAME=Alex AGAMI_ADMIN_LAST_NAME=Kim \
49
+ AGAMI_ADMIN_PASSWORD=… \
50
+ AGAMI_ADMIN_PROVIDER=google \
51
+ AGAMI_OIDC_GOOGLE_CLIENT_ID=… AGAMI_OIDC_GOOGLE_CLIENT_SECRET=… \
52
+ python -m mcp_http
53
+ ```
54
+
55
+ The admin is identified by **email** (`AGAMI_ADMIN_USERNAME`). Their sign-in method is whatever you
56
+ configure — **a password and/or a pinned social provider, at least one**: set `AGAMI_ADMIN_PASSWORD`,
57
+ and/or `AGAMI_ADMIN_PROVIDER` (`google` | `microsoft`, which must also have its
58
+ `AGAMI_OIDC_<PROVIDER>_CLIENT_ID/SECRET` set). The admin login then offers the same Google/Microsoft
59
+ option as the MCP login. Register **one** OAuth redirect URI with the provider —
60
+ `{base}/oauth/oidc/callback` — it serves both the connector and the admin flows.
61
+
62
+ ### One host, two entry points
63
+
64
+ A deployment is one host (`PUBLIC_BASE_URL`). Everything lives under it:
65
+
66
+ | URL | Who | What |
67
+ |---|---|---|
68
+ | `{base}/mcp` | a teammate, in Claude | the **only** URL to add as a custom connector — Claude auto-discovers the OAuth endpoints from it |
69
+ | `{base}/admin` | the admin, in a browser | the console to add/enable/disable users |
70
+
71
+ ### Access model — two separate credentials
72
+
73
+ - **Query surface (`/mcp`)** — gated by a **Bearer JWT** from the OAuth flow. **Any** onboarded user
74
+ who signs in can query (that's the product). No token → `401` + `WWW-Authenticate`, which starts
75
+ Claude's OAuth. Admin-ness does **not** gate `/mcp`.
76
+ - **Admin surface (`/admin`)** — gated by a **session cookie** *and* the admin-gate
77
+ (`AGAMI_ADMIN_USERNAME`). The admin signs in with their **pinned** social provider or a password; a
78
+ valid non-admin is refused (and a social identity for the admin email via a *different* provider is
79
+ refused — the pin closes IdP-confusion). An `/mcp` bearer token is useless here (different
80
+ credential). Unset `AGAMI_ADMIN_USERNAME` ⇒ the admin console is disabled entirely.
81
+
82
+ ### Onboarding a teammate
83
+
84
+ The admin adds a teammate by **email + name** (a *pending* user). How they finish setting up follows
85
+ the deployment's **single auth method** — uniform for everyone, set by what you configured:
86
+
87
+ - **OIDC deployment** (a Google/Microsoft client is configured): the teammate just adds `{base}/mcp` to
88
+ Claude and signs in with that provider — the IdP verifies their email and binds the account on first
89
+ login. No link to share.
90
+ - **Password deployment** (no OIDC configured): the admin **copies the teammate's setup link** from the
91
+ Users tab and shares it out-of-band; the teammate opens it and sets their own password. The link is a
92
+ signed, time-boxed token and is single-use (it stops working once the account is set up).
93
+
94
+ The login surfaces show only the configured method (the admin keeps a password **break-glass** fallback
95
+ on `/admin/login`).
96
+
97
+ > **Trust note.** OIDC onboarding binds the account to whoever first proves the teammate's email at the
98
+ > configured IdP — so add a teammate by an email the *right* person controls there. The setup link and
99
+ > the other pre-auth endpoints aren't rate-limited in-process; put them behind your proxy/LB if exposed.
100
+
101
+ ### Activity view
102
+
103
+ The admin console has one read-only **Activity** tab: every MCP tool call, folded into the conversation
104
+ it belongs to — **thread (conversation) ▸ turn (one user question) ▸ call**. Open a conversation and you
105
+ see its whole arc, *not just the queries*: the `list_datasources` / `get_datasource_schema` calls that
106
+ scoped the work sit alongside the `execute_sql`s that answered it (*"User asked what datasources →
107
+ `list_datasources`; user asked revenue by region → `get_datasource_schema`, then `execute_sql` ×2"*). A
108
+ query call shows its SQL, row count, latency, and status; a non-query call shows its tool name. Every
109
+ call carries its **own** datasource, because a conversation — or even a single turn — can span several:
110
+ the user switches datasource mid-session, or asks something that runs one query per datasource. The
111
+ conversation row lists the full set it touched.
112
+
113
+ The split is deliberate: it is **audit-grade for *what* ran** — the server observes every call directly,
114
+ so nothing is dropped — and **best-effort for *how* it's grouped**. The MCP protocol carries neither the
115
+ user's question, a conversation id, nor a turn boundary, so Claude self-reports them on every call: a
116
+ `user_question` (kept verbatim), a `thread_id` (per conversation), and a `correlation_id` (per turn). The
117
+ turn's question is taken from the **first** call in the turn (the model sometimes drifts it on later
118
+ refinements). When Claude doesn't supply the ids, a call simply shows as its own singleton conversation —
119
+ the view degrades, never drops a call. Treat the self-reported grouping as a hint, not a record.
120
+
121
+ > **Free-tier limit.** A turn that produces **no** tool call — Claude answering "let's continue" from
122
+ > context — never reaches the server and so can't appear here; this is an audit of what ran against your
123
+ > data, not a chat transcript.
124
+
125
+ The `tool_calls` log grows one row per call and has **no automatic retention** — it's your local store,
126
+ so prune it on your own schedule if it gets large.
127
+
128
+ ### Model view
129
+
130
+ The **Model** tab (`{base}/admin/model`) is a **read-only** explorer of the semantic model you've
131
+ deployed — the same tree the MCP tools serve, so it can't drift from what Claude actually reads. It's a
132
+ catalog: a browse rail (datasource → subject area → table) and one page at a time —
133
+
134
+ - a **datasource overview** (description, glossary, storage-connection names/types, the subject areas),
135
+ - a **subject-area landing** (its tables, metrics, entities),
136
+ - a **table page** — the schema, with each column's type and description, and flags only where they
137
+ carry signal (**PK / FK / sensitive / unit / enum / caveat**). Trust is shown as a single table-level
138
+ **confidence** badge; **caveats** (the domain gotchas) are elevated to a callout; wide tables collapse
139
+ behind "show all N", and tables that author `column_groups` render those as collapsible sections,
140
+ - a **Relationships** page (when the model has cross-area joins) — the org-level relationships that
141
+ span subject areas, **grouped by area-pair**, so the cross-area topology is readable in one place,
142
+ - a **domain-context** page (your `ORGANIZATION.md`, rendered as safe markdown).
143
+
144
+ It is **read-only by construction** — a single GET endpoint, no write path. Editing the model stays
145
+ conversational in Claude (the in-app editor is a Hosted feature); connection **credentials are never
146
+ rendered** (names and types only). Deploy a change in Claude and it shows up here on the next deploy.
147
+
148
+ ### Local end-to-end test (HTTPS via a tunnel)
149
+
150
+ OAuth and the `Secure` admin cookie need HTTPS, so expose the local server through a tunnel:
151
+
152
+ ```bash
153
+ # terminal 1 — the server
154
+ PUBLIC_BASE_URL=https://<your-subdomain>.trycloudflare.com \
155
+ AGAMI_SIGNING_SECRET=$(openssl rand -hex 32) \
156
+ AGAMI_DB_URL=sqlite:///$PWD/agami.db \
157
+ AGAMI_ADMIN_USERNAME=you@example.com AGAMI_ADMIN_PASSWORD=choose-a-strong-one \
158
+ python -m mcp_http
159
+
160
+ # terminal 2 — the HTTPS tunnel (prints the https URL to use as PUBLIC_BASE_URL)
161
+ cloudflared tunnel --url http://127.0.0.1:8000
162
+ ```
163
+
164
+ Open `{base}/admin`, sign in, add a user — then add `{base}/mcp` as a connector in Claude.
@@ -0,0 +1,51 @@
1
+ # agami-core — the importable library behind the agami skill and the MCP server: the semantic
2
+ # model, the shared MCP TOOLS harness, and the unified local query executor.
3
+ #
4
+ # Flat top-level module names (semantic_model, mcp_harness, execute_sql, agami_paths) are an
5
+ # invariant: a consumer's imports must resolve unchanged. The src/ layout keeps the importable
6
+ # names flat while keeping them out of an accidental-import top level.
7
+
8
+ [build-system]
9
+ requires = ["setuptools>=68"]
10
+ build-backend = "setuptools.build_meta"
11
+
12
+ [project]
13
+ name = "agami-core"
14
+ version = "0.3.2"
15
+ description = "agami-core — governed semantic model, the shared MCP TOOLS harness, and the unified local query executor."
16
+ readme = "README.md"
17
+ requires-python = ">=3.10"
18
+ license = "LicenseRef-Agami-FUL"
19
+ authors = [{ name = "Agami AI", email = "skills@agami.ai" }]
20
+ # The executor + stdio harness are deliberately pure-stdlib (the local no-egress executor
21
+ # runs SQL with only a DB driver). The model deps live in the [model] extra so the
22
+ # Python-driver tier stays lean; `sm` / the server install [model].
23
+ dependencies = []
24
+
25
+ [project.optional-dependencies]
26
+ model = [
27
+ "pydantic>=2,<3",
28
+ "PyYAML>=6",
29
+ "sqlglot>=20",
30
+ ]
31
+ # The HTTP MCP transport (mcp_http): the official MCP SDK + an ASGI server. Kept out of the base
32
+ # install so the local executor/skill stay stdlib-lean — only a hosted deployment installs it.
33
+ server = [
34
+ "mcp>=1.2",
35
+ "uvicorn>=0.30",
36
+ "psycopg2-binary>=2.9",
37
+ "argon2-cffi>=23",
38
+ "PyJWT>=2.8",
39
+ "httpx>=0.27", # OIDC discovery + token exchange (the server's one outbound egress)
40
+ "cryptography>=43", # RS256 backend for PyJWT id-token verification
41
+ ]
42
+
43
+ [tool.setuptools]
44
+ package-dir = { "" = "src" }
45
+ # Flat top-level modules (not under a parent package) — listed explicitly so the import
46
+ # names stay flat regardless of disk layout.
47
+ py-modules = ["agami_paths", "execute_sql", "mcp_harness", "mcp_http", "tools", "ports", "contracts", "oss_adapters", "store", "model_store", "model_deploy", "deploy_preflight", "oauth_server", "oidc", "passwords", "user_store", "admin", "ui", "onboarding"]
48
+ packages = ["semantic_model"]
49
+
50
+ [tool.setuptools.package-data]
51
+ semantic_model = ["requirements.txt"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+