databricks-agentbricks 0.2.0__py3-none-any.whl

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 (159) hide show
  1. databricks_agentbricks/__init__.py +1 -0
  2. databricks_agentbricks/_group.py +217 -0
  3. databricks_agentbricks/agent_project.py +657 -0
  4. databricks_agentbricks/app_resources.py +139 -0
  5. databricks_agentbricks/cli/__init__.py +12 -0
  6. databricks_agentbricks/cli/app.py +108 -0
  7. databricks_agentbricks/cli/app_auth.py +198 -0
  8. databricks_agentbricks/cli/auth.py +142 -0
  9. databricks_agentbricks/cli/deploy.py +954 -0
  10. databricks_agentbricks/cli/dev.py +310 -0
  11. databricks_agentbricks/cli/endpoint.py +145 -0
  12. databricks_agentbricks/cli/endpoint_examples.py +33 -0
  13. databricks_agentbricks/cli/endpoint_output.py +53 -0
  14. databricks_agentbricks/cli/endpoint_request.py +71 -0
  15. databricks_agentbricks/cli/endpoint_transport.py +148 -0
  16. databricks_agentbricks/cli/help.py +467 -0
  17. databricks_agentbricks/cli/init.py +496 -0
  18. databricks_agentbricks/cli/mcp.py +75 -0
  19. databricks_agentbricks/cli/memory.py +520 -0
  20. databricks_agentbricks/cli/sandbox.py +823 -0
  21. databricks_agentbricks/cli/sessions.py +588 -0
  22. databricks_agentbricks/cli/tools.py +456 -0
  23. databricks_agentbricks/cli/tracing.py +724 -0
  24. databricks_agentbricks/databricks_cli.py +38 -0
  25. databricks_agentbricks/errors.py +114 -0
  26. databricks_agentbricks/lakebase_runtime_store.py +107 -0
  27. databricks_agentbricks/legacy_lakebase_runtime_store.py +74 -0
  28. databricks_agentbricks/project_config.py +157 -0
  29. databricks_agentbricks/project_types.py +55 -0
  30. databricks_agentbricks/py.typed +0 -0
  31. databricks_agentbricks/render.py +349 -0
  32. databricks_agentbricks/templates/agent-bricks-migrate/SKILL.md +101 -0
  33. databricks_agentbricks/templates/agent-langgraph/.env.example +36 -0
  34. databricks_agentbricks/templates/agent-langgraph/.gitignore +199 -0
  35. databricks_agentbricks/templates/agent-langgraph/AGENTKIT_CONTRACT.md +95 -0
  36. databricks_agentbricks/templates/agent-langgraph/AGENTS.md +31 -0
  37. databricks_agentbricks/templates/agent-langgraph/CLAUDE.md +1 -0
  38. databricks_agentbricks/templates/agent-langgraph/README.md +141 -0
  39. databricks_agentbricks/templates/agent-langgraph/agent/__init__.py +0 -0
  40. databricks_agentbricks/templates/agent-langgraph/agent/agent.py +177 -0
  41. databricks_agentbricks/templates/agent-langgraph/agent/mcps.py +27 -0
  42. databricks_agentbricks/templates/agent-langgraph/agent/tools/__init__.py +24 -0
  43. databricks_agentbricks/templates/agent-langgraph/agent/tools/sample_tool.py +15 -0
  44. databricks_agentbricks/templates/agent-langgraph/agent/tools/send_message.py +17 -0
  45. databricks_agentbricks/templates/agent-langgraph/app.yaml +15 -0
  46. databricks_agentbricks/templates/agent-langgraph/pyproject.toml +42 -0
  47. databricks_agentbricks/templates/agent-langgraph/runtime/__init__.py +0 -0
  48. databricks_agentbricks/templates/agent-langgraph/runtime/adapter.py +144 -0
  49. databricks_agentbricks/templates/agent-langgraph/runtime/main.py +25 -0
  50. databricks_agentbricks/templates/agent-langgraph/tests/__init__.py +0 -0
  51. databricks_agentbricks/templates/agent-langgraph/tests/test_agent.py +211 -0
  52. databricks_agentbricks/templates/agent-langgraph/tests/test_runtime.py +19 -0
  53. databricks_agentbricks/templates/agent-langgraph/tests/test_workspace.py +28 -0
  54. databricks_agentbricks/templates/agent-openai/.env.example +37 -0
  55. databricks_agentbricks/templates/agent-openai/.gitignore +199 -0
  56. databricks_agentbricks/templates/agent-openai/AGENTKIT_CONTRACT.md +107 -0
  57. databricks_agentbricks/templates/agent-openai/AGENTS.md +76 -0
  58. databricks_agentbricks/templates/agent-openai/CLAUDE.md +1 -0
  59. databricks_agentbricks/templates/agent-openai/README.md +143 -0
  60. databricks_agentbricks/templates/agent-openai/agent/__init__.py +0 -0
  61. databricks_agentbricks/templates/agent-openai/agent/agent.py +205 -0
  62. databricks_agentbricks/templates/agent-openai/agent/mcps.py +28 -0
  63. databricks_agentbricks/templates/agent-openai/agent/tools/__init__.py +24 -0
  64. databricks_agentbricks/templates/agent-openai/agent/tools/sample_tool.py +15 -0
  65. databricks_agentbricks/templates/agent-openai/agent/tools/send_message.py +18 -0
  66. databricks_agentbricks/templates/agent-openai/app.yaml +15 -0
  67. databricks_agentbricks/templates/agent-openai/pyproject.toml +42 -0
  68. databricks_agentbricks/templates/agent-openai/runtime/__init__.py +0 -0
  69. databricks_agentbricks/templates/agent-openai/runtime/adapter.py +188 -0
  70. databricks_agentbricks/templates/agent-openai/runtime/main.py +25 -0
  71. databricks_agentbricks/templates/agent-openai/tests/__init__.py +0 -0
  72. databricks_agentbricks/templates/agent-openai/tests/test_agent.py +326 -0
  73. databricks_agentbricks/templates/agent-openai/tests/test_runtime.py +19 -0
  74. databricks_agentbricks/templates/agent-openai/tests/test_workspace.py +28 -0
  75. databricks_agentbricks/templates/custom-agent-langgraph/.env.example +1 -0
  76. databricks_agentbricks/templates/custom-agent-langgraph/.gitignore +11 -0
  77. databricks_agentbricks/templates/custom-agent-langgraph/README.md +22 -0
  78. databricks_agentbricks/templates/custom-agent-langgraph/agent/__init__.py +0 -0
  79. databricks_agentbricks/templates/custom-agent-langgraph/agent/agent.py +27 -0
  80. databricks_agentbricks/templates/custom-agent-langgraph/app.yaml +1 -0
  81. databricks_agentbricks/templates/custom-agent-langgraph/pyproject.toml +38 -0
  82. databricks_agentbricks/templates/custom-agent-langgraph/runtime/__init__.py +0 -0
  83. databricks_agentbricks/templates/custom-agent-langgraph/runtime/main.py +31 -0
  84. databricks_agentbricks/templates/custom-agent-langgraph/tests/test_runtime.py +29 -0
  85. databricks_agentbricks/templates/custom-agent-openai/.env.example +1 -0
  86. databricks_agentbricks/templates/custom-agent-openai/.gitignore +11 -0
  87. databricks_agentbricks/templates/custom-agent-openai/README.md +22 -0
  88. databricks_agentbricks/templates/custom-agent-openai/agent/__init__.py +0 -0
  89. databricks_agentbricks/templates/custom-agent-openai/agent/agent.py +29 -0
  90. databricks_agentbricks/templates/custom-agent-openai/app.yaml +1 -0
  91. databricks_agentbricks/templates/custom-agent-openai/pyproject.toml +38 -0
  92. databricks_agentbricks/templates/custom-agent-openai/runtime/__init__.py +0 -0
  93. databricks_agentbricks/templates/custom-agent-openai/runtime/main.py +31 -0
  94. databricks_agentbricks/templates/custom-agent-openai/tests/test_runtime.py +29 -0
  95. databricks_agentbricks/templates/sandbox_mcp.py +39 -0
  96. databricks_agentbricks/templates/sandbox_mcp_langgraph.py +39 -0
  97. databricks_agentbricks/templates/ui/agent-langgraph/CHAT_APP.md +49 -0
  98. databricks_agentbricks/templates/ui/agent-langgraph/runtime/main.py +26 -0
  99. databricks_agentbricks/templates/ui/agent-langgraph/runtime/ui.py +528 -0
  100. databricks_agentbricks/templates/ui/agent-langgraph/tests/test_demo_ui.py +542 -0
  101. databricks_agentbricks/templates/ui/agent-langgraph/ui/agentbricks-mark.png +0 -0
  102. databricks_agentbricks/templates/ui/agent-langgraph/ui/app.js +1464 -0
  103. databricks_agentbricks/templates/ui/agent-langgraph/ui/index.html +281 -0
  104. databricks_agentbricks/templates/ui/agent-langgraph/ui/styles.css +1913 -0
  105. databricks_agentbricks/templates/ui/agent-openai/CHAT_APP.md +54 -0
  106. databricks_agentbricks/templates/ui/agent-openai/runtime/main.py +26 -0
  107. databricks_agentbricks/templates/ui/agent-openai/runtime/ui.py +521 -0
  108. databricks_agentbricks/templates/ui/agent-openai/tests/test_demo_ui.py +512 -0
  109. databricks_agentbricks/templates/ui/agent-openai/ui/agentbricks-mark.png +0 -0
  110. databricks_agentbricks/templates/ui/agent-openai/ui/app.js +1428 -0
  111. databricks_agentbricks/templates/ui/agent-openai/ui/index.html +281 -0
  112. databricks_agentbricks/templates/ui/agent-openai/ui/styles.css +1913 -0
  113. databricks_agentbricks/theme.py +72 -0
  114. databricks_agentbricks-0.2.0.dist-info/METADATA +897 -0
  115. databricks_agentbricks-0.2.0.dist-info/RECORD +159 -0
  116. databricks_agentbricks-0.2.0.dist-info/WHEEL +4 -0
  117. databricks_agentbricks-0.2.0.dist-info/entry_points.txt +2 -0
  118. databricks_agentbricks-0.2.0.dist-info/licenses/NOTICE +39 -0
  119. databricks_agentkit/__init__.py +67 -0
  120. databricks_agentkit/_api_client.py +673 -0
  121. databricks_agentkit/_pagination.py +25 -0
  122. databricks_agentkit/client.py +31 -0
  123. databricks_agentkit/langgraph/__init__.py +98 -0
  124. databricks_agentkit/langgraph/genie.py +50 -0
  125. databricks_agentkit/langgraph/mcp.py +216 -0
  126. databricks_agentkit/langgraph/memory.py +67 -0
  127. databricks_agentkit/langgraph/session_store.py +485 -0
  128. databricks_agentkit/memory_store.py +371 -0
  129. databricks_agentkit/models.py +330 -0
  130. databricks_agentkit/openai/__init__.py +93 -0
  131. databricks_agentkit/openai/genie.py +50 -0
  132. databricks_agentkit/openai/mcp.py +189 -0
  133. databricks_agentkit/openai/memory.py +67 -0
  134. databricks_agentkit/openai/sessions.py +157 -0
  135. databricks_agentkit/py.typed +0 -0
  136. databricks_agentkit/runtime/ARCHITECTURE.md +64 -0
  137. databricks_agentkit/runtime/README.md +184 -0
  138. databricks_agentkit/runtime/__init__.py +69 -0
  139. databricks_agentkit/runtime/app.py +316 -0
  140. databricks_agentkit/runtime/auth.py +149 -0
  141. databricks_agentkit/runtime/durability/__init__.py +1 -0
  142. databricks_agentkit/runtime/durability/execution.py +133 -0
  143. databricks_agentkit/runtime/durability/heartbeat.py +64 -0
  144. databricks_agentkit/runtime/durability/lakebase_runtime_store.py +648 -0
  145. databricks_agentkit/runtime/durability/recovery.py +70 -0
  146. databricks_agentkit/runtime/durability/store.py +33 -0
  147. databricks_agentkit/runtime/execution.py +160 -0
  148. databricks_agentkit/runtime/genie.py +224 -0
  149. databricks_agentkit/runtime/mcp_auth.py +114 -0
  150. databricks_agentkit/runtime/model_services.py +90 -0
  151. databricks_agentkit/runtime/runtime.py +273 -0
  152. databricks_agentkit/runtime/session_store_client.py +120 -0
  153. databricks_agentkit/runtime/store.py +287 -0
  154. databricks_agentkit/runtime/tool_manifest.py +223 -0
  155. databricks_agentkit/runtime/tracing.py +71 -0
  156. databricks_agentkit/runtime/types.py +118 -0
  157. databricks_agentkit/runtime/workspace.py +27 -0
  158. databricks_agentkit/session_store.py +434 -0
  159. databricks_agentkit/timefmt.py +85 -0
@@ -0,0 +1,897 @@
1
+ Metadata-Version: 2.5
2
+ Name: databricks-agentbricks
3
+ Version: 0.2.0
4
+ Summary: Agent Bricks CLI and AgentKit SDK for custom agents on Databricks
5
+ Author-email: Databricks <agent-feedback@databricks.com>
6
+ License-File: NOTICE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: click>=8.4
9
+ Requires-Dist: databricks-ai-bridge[memory]>=0.22.0
10
+ Requires-Dist: databricks-sdk>=0.124.0
11
+ Requires-Dist: fastapi>=0.129.0
12
+ Requires-Dist: mlflow-skinny>=3.10.1
13
+ Requires-Dist: psycopg[binary]>=3.1
14
+ Requires-Dist: pyyaml>=6.0
15
+ Requires-Dist: rich>=13.7
16
+ Requires-Dist: sqlalchemy[asyncio]>=2.0
17
+ Requires-Dist: tomli>=2.0
18
+ Requires-Dist: tomlkit>=0.13
19
+ Requires-Dist: uvicorn>=0.20.0
20
+ Provides-Extra: langgraph
21
+ Requires-Dist: databricks-agents>=1.9.3; extra == 'langgraph'
22
+ Requires-Dist: databricks-langchain>=0.17.0; extra == 'langgraph'
23
+ Requires-Dist: langchain-mcp-adapters>=0.2.1; extra == 'langgraph'
24
+ Requires-Dist: langchain>=1.0.0; extra == 'langgraph'
25
+ Requires-Dist: langgraph>=1.1.0; extra == 'langgraph'
26
+ Requires-Dist: mlflow>=3.10.1; extra == 'langgraph'
27
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25.0; extra == 'langgraph'
28
+ Provides-Extra: openai
29
+ Requires-Dist: databricks-agents>=1.9.3; extra == 'openai'
30
+ Requires-Dist: databricks-openai>=0.13.0; extra == 'openai'
31
+ Requires-Dist: mlflow>=3.10.1; extra == 'openai'
32
+ Requires-Dist: openai-agents>=0.8.0; extra == 'openai'
33
+ Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.25.0; extra == 'openai'
34
+ Description-Content-Type: text/markdown
35
+
36
+ # Agent Bricks CLI (`ab`)
37
+
38
+ Agent Bricks CLI is an experimental command-line interface for building and deploying custom
39
+ agents on Databricks. It manages memory, sessions, tracing, and deployments from one authenticated
40
+ command.
41
+
42
+ > The underlying APIs are in preview and may need workspace enablement.
43
+
44
+ ## Overview
45
+
46
+ A managed path from your custom agent code to a production-ready, scalable, durable agent hosted on
47
+ Databricks in minutes - with no server framework to build, no infrastructure to provision, and no
48
+ invocation protocol to design yourself. Bring your own agent, or start from a template.
49
+
50
+ - **Deployment** - a guided lifecycle (scaffold, run locally, deploy) that turns an agent project
51
+ into a hosted endpoint. Databricks provisions the compute, the stores your agent binds (session,
52
+ memory), and the access grants, so you ship application code and get a running endpoint.
53
+ - **Runtime** - a managed HTTP invocation contract (synchronous, streaming, background) plus optional
54
+ durable execution (persistence, heartbeats, crash recovery) backed by Databricks Lakebase, with no
55
+ database or job queue to operate. Use the opinionated `DurableAgentServer` to get it out of the box,
56
+ or bring your own server for full control. `AgentApp` remains available as a deprecated
57
+ compatibility alias; new code should use `DurableAgentServer`.
58
+
59
+ **Deployment**
60
+
61
+ ![Deployment: from a blank directory to a running service](docs/deployment.svg)
62
+
63
+ - **Agent project** - `ab init` scaffolds a deployable project from a framework template
64
+ (LangGraph or OpenAI Agents) with the runtime, tests, and an optional chat UI wired up; you edit
65
+ the application code (model, tools, prompts).
66
+ - **`agent.toml`** - the declarative source of truth for the Databricks-managed infrastructure your
67
+ agent depends on: tool bindings (data sandbox, managed MCP services, Unity Catalog functions) and
68
+ memory, session, and durability resources. `ab deploy` reads it to provision and wire everything
69
+ up (detailed under [Agent tools](#agent-tools)).
70
+ - **`ab deploy`** - provisions the bound stores, grants the app's service principal access to
71
+ them, provisions the durable-runtime database when durability is on, configures tracing, and rolls
72
+ out the app. `ab deployments` covers the lifecycle (list, get, logs, start, stop, delete).
73
+ - **`ab dev`** - runs your agent from the same manifest the deployment uses, so local behavior
74
+ matches what ships.
75
+
76
+ **Runtime**
77
+
78
+ ![Runtime: one FastAPI server, run as DurableAgentServer or your own implementation](docs/runtime.svg)
79
+
80
+ The two ways to run an agent:
81
+
82
+ - **`DurableAgentServer` - opinionated, batteries included.** Register one handler and get the managed
83
+ invocation contract (synchronous, streaming, background). Enable the durable runtime so
84
+ long-running and background work survives restarts, redeploys, and crashes. The framework
85
+ templates are thin layers over `DurableAgentServer` (HTTP contract detailed under [Runtime](#runtime)).
86
+ - **Custom server - generic, full control.** `ab init --server custom` scaffolds a minimal FastAPI
87
+ server with no `DurableAgentServer`: you define your own endpoints, request/response shapes, and protocol.
88
+ `ab dev` and `ab deploy` run and ship it the same way.
89
+
90
+ ## Prerequisites
91
+
92
+ - **Python ≥3.10** — the `ab` CLI installs and runs on any Python 3.10+. The
93
+ `memory`, `sessions`, `tools`, and `ab tracing bind`/`unbind` commands need nothing else.
94
+ - **[`uv`](https://docs.astral.sh/uv/)** — needed to scaffold, run, and deploy an
95
+ agent (`ab init` → `ab dev` → `ab deploy`): the scaffolded project builds
96
+ its environment and launches with `uv run`, both locally and in the deployed Apps
97
+ runtime. The store/session/tools commands and `ab tracing bind`/`unbind` don't need it;
98
+ `ab tracing list`/`get` do, to read `ab dev`'s local trace store.
99
+ - **[Databricks CLI](https://docs.databricks.com/dev-tools/cli/)** — needed for
100
+ browser-based `ab login`. If a profile is already authenticated, the CLI uses it
101
+ directly and the Databricks CLI is optional.
102
+
103
+ ## Installation
104
+
105
+ From PyPI:
106
+
107
+ The `databricks-agentbricks` Python distribution installs the `ab` command and AgentKit.
108
+
109
+ ```sh
110
+ pip install databricks-agentbricks
111
+ ```
112
+
113
+ From source:
114
+
115
+ ```sh
116
+ pip install 'git+https://github.com/databricks/databricks-ai-bridge.git#subdirectory=integrations/agentbricks'
117
+ ```
118
+
119
+ The base package includes the CLI, store SDK, and `DurableAgentServer` HTTP runtime. Generated projects
120
+ declare their framework dependencies automatically.
121
+
122
+ ## Shell completion
123
+ Add this to `~/.zshrc`:
124
+ ```sh
125
+ eval "$(_AB_COMPLETE=zsh_source ab)"
126
+ ```
127
+
128
+ ## Authentication
129
+
130
+ Agent Bricks CLI uses [Databricks authentication](https://docs.databricks.com/aws/en/dev-tools/cli/authentication).
131
+ Ask the CLI to authenticate and remember a named profile:
132
+
133
+ ```sh
134
+ ab login --profile <profile>
135
+ ab sessions stores list
136
+ ```
137
+
138
+ `ab login` validates existing credentials first. If credentials are missing or rejected in
139
+ an interactive terminal, the CLI runs `databricks auth login --profile <profile>`, revalidates the
140
+ profile, and stores the selection in the existing `~/.agentbricks/config.json` state file. This
141
+ browser-based setup requires the Databricks CLI. In non-interactive environments, authenticate the
142
+ profile before running `ab`. `ab logout` forgets the saved selection without revoking the underlying
143
+ credentials.
144
+
145
+ If Databricks SDK default authentication is already configured, you can skip `ab login`.
146
+ You can also pass the global `--profile/-p` option before an individual command, for example
147
+ `ab --profile <profile> tools list`. Use `--output json` for scripting.
148
+
149
+ ## Quickstart
150
+
151
+ The shortest path from a blank directory to a running and deployed agent:
152
+
153
+ ```sh
154
+ ab login --profile <profile>
155
+ ab init my-agent
156
+ cd my-agent
157
+ ab dev # run locally
158
+ ab deploy my-agent # deploy to Databricks
159
+ ```
160
+
161
+ `ab dev` runs the agent locally on `http://localhost:8000`, wrapping the Databricks Apps
162
+ local runtime so local behavior matches a deployment.
163
+
164
+ `ab deploy my-agent` deploys a Databricks App named `agent-bricks-my-agent`, provisions the
165
+ stores declared in `agent.toml`, and grants the app's service principal access to them. Use
166
+ `ab deployments list` to find deployed apps, and `ab deployments get agent-bricks-my-agent` to
167
+ print an app's URL and status.
168
+
169
+ `ab init` declares default memory and session stores in `agent.toml`, so the deployed agent has
170
+ long-term memory and durable conversation history. It creates `<name>-<6-letter-token>-memory` and
171
+ `<name>-<6-letter-token>-sessions`, and records both names in `agent.toml`.
172
+ `ab deploy` creates them if they don't exist yet. Point the agent at stores you already have with
173
+ `ab memory bind <name>` / `ab sessions bind <name>`, or scaffold without stores using
174
+ `ab init --server custom` (see [Initialize the chat app demo](#initialize-the-chat-app-demo)).
175
+
176
+ To exercise the agent (locally under `ab dev` or once deployed), `ab endpoint invoke` sends
177
+ it an HTTP request. MLflow tracing is on by default (`ab init` binds a default
178
+ `/Shared/agentbricks_traces/<project>` experiment): `ab dev` traces to a local MLflow server under
179
+ `.agentbricks/` and `ab deploy` to the bound workspace experiment; `ab tracing list` shows the
180
+ available traces.
181
+
182
+ ## Public names
183
+
184
+ Use `ab` for the CLI and `AgentKitClient` from `databricks_agentkit` for the Python SDK. New
185
+ projects store local state under `.agentbricks/` and `~/.agentbricks/`, use
186
+ `server = "agentbricks"` in `agent.toml`, and deploy apps with the `agent-bricks-` prefix.
187
+
188
+ ## AgentKit SDK
189
+
190
+ `AgentKitClient` adds a small resource-oriented layer over AgentKit APIs. Pass it an
191
+ authenticated Databricks `WorkspaceClient`, or omit the argument to use the
192
+ Databricks SDK's default authentication resolution:
193
+
194
+ ```python
195
+ from databricks.sdk import WorkspaceClient
196
+ from databricks_agentkit import AgentKitClient
197
+
198
+ agentkit = AgentKitClient(WorkspaceClient(profile="my-workspace"))
199
+
200
+ session_store = agentkit.session_stores.create("support-agent-sessions")
201
+ session = session_store.add(actor_id="customer-123", session_id="case-456")
202
+ session.append_items(
203
+ [
204
+ {"type": "message", "role": "user", "content": "I need help with my cluster."},
205
+ {"type": "message", "role": "assistant", "content": "Let's take a look."},
206
+ ]
207
+ )
208
+
209
+ memory_store = agentkit.memory_stores.create("coding-agent-memory")
210
+ memory = memory_store.add(
211
+ actor_id="alice",
212
+ path="/preferences/style.md",
213
+ content="The user prefers concise answers.",
214
+ )
215
+ results = memory_store.search(
216
+ actor_id="alice",
217
+ query="response preferences",
218
+ limit=10,
219
+ )
220
+ memory = memory.update(content="The user prefers very concise answers.")
221
+ memory.delete()
222
+ ```
223
+
224
+ The root collections manage stores: `agentkit.memory_stores.create/get/list` and
225
+ `agentkit.session_stores.create/get/list`. A returned store owns operations on its
226
+ contents, such as `memory_store.add()`, `memory_store.get("memory-id")`,
227
+ `memory_store.list()`, and `memory_store.search()`, or `session_store.add()`,
228
+ `session_store.get("session-id")`, and `session_store.list()`. Returned memories,
229
+ sessions, and stores own their `update()` and `delete()` operations.
230
+
231
+ All `list()` methods return iterators that automatically consume server pages. List
232
+ `page_size` and search `limit` values must be between 1 and 100. `session.list_items()`
233
+ also auto-pages. `session.fork(...)` creates an independent copy, optionally through
234
+ a specific item. Deleting a session with descendants requires
235
+ `session.delete(force=True)` to cascade the deletion.
236
+
237
+ The resource layer intentionally does not mirror every API method. Its private
238
+ transport will be replaced by the generated `WorkspaceClient.mason` service when that
239
+ is released, without changing this public surface. Deployment, sandbox, tracing, and
240
+ the existing CLI commands remain separate.
241
+
242
+ ## Runtime
243
+
244
+ `DurableAgentServer` runs your agent through one HTTP API for synchronous, streaming, and background
245
+ invocations. Register an `@app.invoke` handler, publish progress with `await context.emit(event)`,
246
+ and return a JSON result. You can also add your own FastAPI endpoints.
247
+
248
+ Start from a template, edit the agent code in `agent/`, and run it locally before deploying:
249
+
250
+ ```sh
251
+ ab init my-agent --framework langgraph --server agentbricks --profile <profile>
252
+ cd my-agent
253
+ ab dev
254
+ # Stop the local server when ready to deploy.
255
+ ab --profile <profile> deploy my-agent
256
+ ```
257
+
258
+ Use `--framework openai` for OpenAI Agents. Templates keep agent code separate from the runtime
259
+ adapter and declare default Session and Memory Store bindings in `agent.toml`.
260
+
261
+ Each managed run is an **invocation**. Send a client-generated UUID `id` and your agent's `input`:
262
+
263
+ ```json
264
+ {
265
+ "id": "550e8400-e29b-41d4-a716-446655440000",
266
+ "input": {"messages": [{"role": "user", "content": "Hello"}]},
267
+ "background": true,
268
+ "stream": true
269
+ }
270
+ ```
271
+
272
+ | Endpoint | Behavior |
273
+ | --- | --- |
274
+ | `POST /api/invocations` | Defaults to synchronous execution: `200` with the result under `output`. `stream: true` returns SSE events. `background: true` returns `202` with a status URL; adding `stream: true` also includes an events URL. |
275
+ | `GET /api/invocations/{id}` | Returns the invocation status and, when completed, its output. |
276
+ | `GET /api/invocations/{id}/events?after={cursor}` | Streams events after the last received event ID, allowing clients to reconnect. |
277
+
278
+ The UUID also acts as an idempotency key: repeating the same request reuses the existing invocation
279
+ while its record is retained; using the ID for a different request returns `409`.
280
+
281
+ `ab dev` keeps execution state in process and loses it on restart. For projects with
282
+ `[agent].server = "agentbricks"`, `ab deploy` provisions a persistent Runtime Store for requests,
283
+ status, events, and results. Register `@app.recover` to restart interrupted app-auth work after
284
+ worker failures. Recovery is at-least-once, so external side effects must be idempotent. Session
285
+ and Memory Stores separately preserve the state used by your agent.
286
+
287
+ The managed path uses the internal Runtime Store API to create a dedicated database in the
288
+ workspace's shared Lakebase project and give the app SP ownership. The managed runtime initializes its schema and
289
+ tables; no manual Lakebase grant or Postgres app-resource attachment is needed. Backend selection
290
+ is an internal rollout detail, not a user-facing setting; the current implementation retains the legacy
291
+ per-app Lakebase project by default. Once enabled, redeploy reads the stored backend and verifies
292
+ the app identity, and `ab deployments delete` removes the managed store before deleting the app.
293
+ The switch does not migrate existing deployments between backends. Managed cleanup errors retain
294
+ the app for retry. Direct app deletion bypasses managed store cleanup.
295
+
296
+ For a tool using `auth = "user"`, the Runtime Store still records token-free invocation state,
297
+ events, and results. The forwarded user credential remains process-local for the active attempt and
298
+ is never written to the Runtime Store. A replacement attempt after failure recovery stops with
299
+ `MCP_USER_AUTH_RECOVERY_UNSUPPORTED` because the original request credential is no longer present.
300
+
301
+ Use `server = "custom"` to deploy your own HTTP server without provisioning a Runtime Store.
302
+ Changing the server type of an existing deployment is not supported. To use a different server,
303
+ scaffold a new project with the desired `ab init --server` option and deploy it under a new name.
304
+ See the [runtime guide](src/databricks_agentkit/runtime/README.md) for agent hooks, full API examples,
305
+ and recovery behavior.
306
+
307
+ ## Memory and sessions
308
+
309
+ To hold context, an agent needs two kinds of state: the state of the interaction it is handling right
310
+ now, and the durable knowledge it carries from one conversation to the next. Databricks provides a
311
+ fully managed store for each, both backed by Lakebase and usable from agents built on any framework:
312
+
313
+ - **Managed agent sessions** store an agent's session state: the state an agent or framework keeps
314
+ for one interaction. Most commonly this is the conversation history (the ordered transcript of
315
+ messages, tool calls, and results), but it can be any state a framework persists, such as a
316
+ LangGraph graph. The agent reads it at the start of a turn and appends to it as the interaction
317
+ runs.
318
+ - **Managed agent memory** stores durable facts, preferences, and decisions that an agent recalls in
319
+ later, separate conversations, retrieved by semantic search.
320
+
321
+ The examples below use the [`AgentKitClient` Python SDK](#agentkit-sdk); the same operations are available
322
+ as `ab sessions` / `ab memory` CLI commands.
323
+
324
+ ![Sessions and memory: the agent reads and appends one conversation's transcript in the session store, and recalls and saves durable facts in the memory store, which outlive any single conversation.](docs/sessions_and_memory.png)
325
+
326
+ ### Sessions
327
+
328
+ A **session store** holds **sessions**, and each session holds an ordered list of **session items**. A
329
+ session is one interaction — typically a conversation thread — grouped under an `actor_id` (who it
330
+ belongs to; set this from trusted application context, never a model- or user-supplied value) and
331
+ identified by a caller-chosen `session_id` (the service generates one if you omit it). Each item is an
332
+ opaque, JSON-compatible `data` value — a message, tool call, result, or reasoning block — that
333
+ Databricks stores and returns verbatim, in order, and never mutates once appended.
334
+
335
+ Create a store, start a session, append the conversation's turns, and read the history back on a later
336
+ request:
337
+
338
+ ```python
339
+ from databricks.sdk import WorkspaceClient
340
+ from databricks_agentkit import AgentKitClient
341
+
342
+ agentkit = AgentKitClient(WorkspaceClient())
343
+
344
+ session_store = agentkit.session_stores.create("support-agent-sessions")
345
+ session = session_store.add(actor_id="customer-123", session_id="case-456")
346
+
347
+ session.append_items(
348
+ [
349
+ {"type": "message", "role": "user", "content": "I need help with my cluster."},
350
+ {"type": "message", "role": "assistant", "content": "Let's take a look."},
351
+ ]
352
+ )
353
+
354
+ # On a later turn, reload the session and read its full history in order.
355
+ session = session_store.get("case-456")
356
+ history = [item.data for item in session.list_items()] # list_items auto-pages
357
+ ```
358
+
359
+ A session can be **forked** into an independent branch: a new session seeded with the original's
360
+ history, linked back to its origin by `parent_session_id`. Fork the full history, or only up to a
361
+ specific item, to explore an alternate continuation without disturbing the original thread:
362
+
363
+ ```python
364
+ branch = session.fork(actor_id="customer-123") # add up_to_item_id=... to branch up to one item
365
+ ```
366
+
367
+ Deleting a session that has such descendants requires `session.delete(force=True)` to cascade.
368
+
369
+ In an agent configured with `server = "agentbricks"`, you don't call these directly — the framework adapter reads and appends
370
+ session state for you. With LangGraph, pass `checkpointer()` when you build the agent and scope each
371
+ run with `thread_config(session_id)`; the OpenAI Agents adapter exposes the same as
372
+ `session_store(session_id)`:
373
+
374
+ ```python
375
+ from databricks_agentkit.langgraph import checkpointer, thread_config
376
+
377
+ agent = create_agent(model=..., tools=[...], checkpointer=checkpointer())
378
+ result = await agent.ainvoke(inputs, config=thread_config(session_id))
379
+ ```
380
+
381
+ ### Memory
382
+
383
+ A **memory store** holds **memory entries**. Each entry is a free-form `content` string plus a short
384
+ `description` used for retrieval, keyed by three fields: `actor_id` (whose memory it is — set from
385
+ trusted application context, never a model- or user-supplied value), `path` (a filesystem-like key
386
+ within an actor, such as `/preferences/response-style.md`), and an optional `session_id` (the session
387
+ an entry came from, for provenance). An entry is uniquely identified by its `actor_id`, `path`, and
388
+ optional `session_id`.
389
+
390
+ Write an entry when the agent learns something durable, then recall it in a later, separate
391
+ conversation with a natural-language search — results are ranked by full-text (BM25) relevance, up to
392
+ 100 entries, with no pagination or vector similarity:
393
+
394
+ ```python
395
+ from databricks.sdk import WorkspaceClient
396
+ from databricks_agentkit import AgentKitClient
397
+
398
+ agentkit = AgentKitClient(WorkspaceClient())
399
+
400
+ memory_store = agentkit.memory_stores.create("support-agent-memory")
401
+ memory_store.add(
402
+ actor_id="user-123",
403
+ path="/preferences/communication.md",
404
+ content="Prefers email over phone. Timezone: PST.",
405
+ description="User 123 communication preferences",
406
+ )
407
+
408
+ # In a later, separate conversation, recall what the agent knows about this user.
409
+ results = memory_store.search(actor_id="user-123", query="communication preferences", limit=10)
410
+ ```
411
+
412
+ To browse rather than search, `memory_store.list(actor_id=..., path_prefix=...)` returns entries
413
+ directly.
414
+
415
+ In an agent configured with `server = "agentbricks"`, add the memory tools so the model can read and write memory during a run.
416
+ `memory_tools(actor)` exposes `remember` and `recall` bound to one actor's partition; it resolves the
417
+ store from the `[memory_store]` binding, carried to the runtime by the `AGENT_MEMORY_STORE` env var
418
+ that `ab deploy` injects, and returns no tools when no store is set, so the agent runs unchanged.
419
+ That "no store set" path is also how it runs under `ab dev`, which runs locally: memory is off
420
+ there (the store is provisioned and used only at deploy). The OpenAI Agents adapter exposes the same as
421
+ `memory_tools()`:
422
+
423
+ ```python
424
+ from databricks_agentkit.langgraph import memory_tools
425
+
426
+ agent = create_agent(model=..., tools=[*your_tools, *memory_tools(actor)])
427
+ ```
428
+
429
+ > **`actor_id` partitions data; it is not access control.** Both stores are workspace-scoped and
430
+ > authorized at the store level, so any principal that can reach a store can read and write every
431
+ > actor's entries. For strict isolation between tenants or users, use a separate store per boundary.
432
+ > Grant another principal — such as your app's service principal — access with
433
+ > `session_store.grant_permission(principal_id)` or `memory_store.grant_permission(principal_id)`;
434
+ > `ab deploy` does this for the deployed app automatically.
435
+
436
+ ### Declaring and provisioning stores
437
+
438
+ For a deployed agent, `agent.toml` declares which stores it uses and `ab deploy` provisions them —
439
+ you don't create stores by hand. `ab init` declares a default memory and session store named from
440
+ the project; override those names, point at stores you already have, or let `deploy` create them:
441
+
442
+ ```sh
443
+ # Scaffold a project with default memory and session stores declared in agent.toml.
444
+ ab init my-agent
445
+
446
+ # Override the declared store names at init time.
447
+ ab init my-agent --memory-store support-agent-memory --session-store support-agent-sessions
448
+
449
+ # Or point an existing project at specific stores (edits agent.toml only; creates nothing).
450
+ ab sessions bind support-agent-sessions
451
+ ab memory bind support-agent-memory
452
+
453
+ # deploy creates any declared-but-missing store and grants the app's service principal access.
454
+ ab deploy my-agent
455
+ ```
456
+
457
+ Memory and session stores are independent resources: deleting one never affects the other.
458
+
459
+ ## Commands
460
+
461
+ For the full command reference - every command, subcommand, argument, and option, in table form -
462
+ see [`cli.md`](cli.md). The tree below is a quick overview.
463
+
464
+ ```text
465
+ ab [-p <profile>] [-o text|json]
466
+ login [--profile P]
467
+ logout
468
+ init [--framework openai|langgraph] [--server agentbricks|custom]
469
+ [--disable-chat-app]
470
+ [--memory-store NAME] [--session-store NAME]
471
+ [--existing] [--profile P] [directory]
472
+ dev [--source PATH] [--prepare-environment] [--app-port PORT]
473
+ memory
474
+ bind STORE [--source PATH]
475
+ unbind [--source PATH]
476
+ stores create | list | get | update | delete
477
+ entries create | get | list | search | update | delete
478
+ sessions create | list | get | update | delete | fork
479
+ bind STORE [--source PATH]
480
+ unbind [--source PATH]
481
+ stores create | list | get | update | delete
482
+ items list | append | pop | clear
483
+ tracing
484
+ bind (--experiment-name NAME | --experiment-id ID) [--source PATH]
485
+ unbind [--source PATH]
486
+ list | get [--experiment-name NAME | --experiment-id ID] [--source PATH]
487
+ tools
488
+ add sandbox --scope SCOPE [--scope SCOPE ...] [--source PATH]
489
+ add mcp SERVICE [--name NAME] [--source PATH]
490
+ add uc-function FUNCTION [--name NAME] [--source PATH]
491
+ add genie-one [--name NAME] [--auth user|app] [--source PATH]
492
+ add genie-agent SPACE_ID [--name NAME] [--auth user|app] [--source PATH]
493
+ list [--kind sandbox|mcp|uc-function|genie-one|genie-agent]
494
+ [--schema CATALOG.SCHEMA]
495
+ remove TOOL_ID [MCP_SERVICE] [--source PATH]
496
+ deploy [<name>] [--source PATH] [--instances N]
497
+ deployments list | get | logs | start | stop | delete
498
+ endpoint
499
+ invoke [APP] --path PATH [--url URL] [--json JSON] [--sse]
500
+ ```
501
+
502
+ ## Bring an existing agent
503
+
504
+ From the existing project, prepare a migration for your coding agent:
505
+
506
+ ```sh
507
+ ab init --framework langgraph --existing .
508
+ ab init --framework openai --existing .
509
+ ```
510
+
511
+ This writes `agent-bricks-migrate/` containing a skill, a prompt to paste into your coding agent,
512
+ `references/migration.json`, and a reference project generated from the templates bundled with the
513
+ installed CLI. The bundle sits outside any single agent's configuration directory; `.claude/skills/`
514
+ and `.agent/skills/` each receive a small skill that points at it, so Claude Code, Codex, and
515
+ similar tools discover the same instructions without duplicating the reference. Agent Bricks CLI
516
+ prepares the instructions; the coding agent performs and verifies the conversion. Init leaves application
517
+ source, dependencies, `.env`, and existing `.agentbricks/project.toml` configuration intact and refuses to overwrite
518
+ existing migration files.
519
+
520
+ The bundle is scaffolding for the migration, not part of the application: delete `agent-bricks-migrate/`
521
+ and the two pointer skills once the conversion is done, and keep them out of commits meanwhile.
522
+
523
+ The skill follows the shared managed-runtime contract for the selected framework, included in new projects and
524
+ migration references:
525
+ [LangGraph](src/databricks_agentbricks/templates/agent-langgraph/AGENTKIT_CONTRACT.md) or
526
+ [OpenAI Agents SDK](src/databricks_agentbricks/templates/agent-openai/AGENTKIT_CONTRACT.md). It explicitly
527
+ handles existing history, custom state and output, recovery, and client/session contracts. For
528
+ LangGraph, switching checkpointers does not migrate old conversations (likewise, the OpenAI Agents
529
+ SDK keeps prior Session transcripts and RunState behind); unresolved transitions require a user
530
+ decision.
531
+
532
+ The reference honors `--disable-chat-app`, `--memory-store`, `--session-store`, and the selected
533
+ profile. These are migration intent; init does not provision resources or change the existing
534
+ application. Migration supports LangGraph and the OpenAI Agents SDK with the managed server (`server = "agentbricks"`);
535
+ `--server custom` is not supported for `--existing`.
536
+
537
+ ## Invoke HTTP endpoints
538
+
539
+ `ab endpoint invoke` is a low-level HTTP command. It resolves and authenticates a deployed
540
+ Databricks App, or targets localhost and arbitrary servers through `--url`. It does not assume an
541
+ agent protocol: provide the method, path, query parameters, and complete JSON body required by the
542
+ server.
543
+
544
+ ```sh
545
+ ab --profile <profile> endpoint invoke agent-bricks-my-agent \
546
+ --path /api/invocations \
547
+ --json '{"id":"00000000-0000-4000-8000-000000000001","input":[{"role":"user","content":"Hello"}]}'
548
+
549
+ ab endpoint invoke --url http://localhost:8000 \
550
+ --path /api/invocations \
551
+ --json '{"id":"00000000-0000-4000-8000-000000000001","input":[{"role":"user","content":"Hello"}]}'
552
+ ```
553
+
554
+ The JSON body remains explicit even for generated agents. For example, managed runtime agents require
555
+ a client-generated invocation ID, and streaming servers require their own streaming field plus
556
+ `--sse` so the CLI consumes the response as Server-Sent Events.
557
+
558
+ ```sh
559
+ INVOCATION_ID=$(uuidgen)
560
+ ab --profile <profile> endpoint invoke agent-bricks-my-agent \
561
+ --path /api/invocations \
562
+ --json "{\"id\":\"$INVOCATION_ID\",\"input\":[{\"role\":\"user\",\"content\":\"Run the report\"}]}"
563
+
564
+ ab --profile <profile> endpoint invoke agent-bricks-my-agent \
565
+ --path /api/invocations \
566
+ --sse \
567
+ --json "{\"id\":\"$INVOCATION_ID\",\"input\":[{\"role\":\"user\",\"content\":\"Hello\"}],\"stream\":true}"
568
+ ```
569
+
570
+ `--session-id` preserves one application session across calls by setting the Databricks Apps routing
571
+ cookie. This also works with a direct App URL and with the generated runtime on localhost. OAuth and
572
+ session headers are managed by the runtime; arbitrary custom request headers are intentionally not exposed
573
+ by this command.
574
+
575
+ ## Command help
576
+
577
+ Use the conventional help flag at any command level. Every command's help includes runnable
578
+ examples:
579
+
580
+ ```sh
581
+ ab --help
582
+ ab deploy --help
583
+ ab sessions items append --help
584
+ ```
585
+
586
+ ## Agent tools
587
+
588
+ For projects with `[agent].server = "agentbricks"` (the default from `ab init`), `agent.toml` is the
589
+ declarative source of truth for Databricks-managed infrastructure: the Runtime Store, sandbox,
590
+ managed MCP, Genie and Unity Catalog function bindings, plus memory and session resources. `ab tools
591
+ add` updates only this file; direct TOML edits have the same behavior. Both managed-server framework
592
+ adapters read the managed bindings at runtime without generating or patching agent source:
593
+
594
+ ```sh
595
+ ab tools add sandbox --scope table:samples.nyctaxi.trips
596
+ ab tools add mcp system.ai.web_search
597
+ ab tools add uc-function catalog.schema.lookup_ticket
598
+ ab tools add genie-one
599
+ ab tools add genie-agent SPACE_ID
600
+ ab tools remove mcp system.ai.web_search
601
+ ab tools list
602
+ ```
603
+
604
+ ### Managed tool identity and migration
605
+
606
+ `ab tools add mcp`, `ab tools add sandbox`, `ab tools add genie-one`, and
607
+ `ab tools add genie-agent` write explicit `auth = "user"` by default.
608
+ Use `--auth app` for the App service principal instead. This field is on the tool entry, not
609
+ inside `source` or `policy`:
610
+
611
+ ```toml
612
+ [[tools]]
613
+ id = "web_search"
614
+ auth = "user"
615
+ source = { kind = "mcp", service = "system.ai.web_search" }
616
+ ```
617
+
618
+ Direct UC-function bindings remain app/default identity and do not accept `--auth user`.
619
+ Managed-tool add commands write the selected identity to `agent.toml`; inspect that manifest to
620
+ review configured bindings. Missing legacy auth continues to mean App identity at runtime; it is
621
+ never silently upgraded to user identity.
622
+
623
+ `DurableAgentServer` derives its request-auth policy directly from the managed tool bindings in `agent.toml`.
624
+ Projects do not maintain a separate request-auth contract marker: the presence of any managed tool
625
+ with `auth = "user"` makes the invocation require a transient request-user credential.
626
+
627
+ Request-user invocations use the same synchronous, streaming, background, status, event-replay,
628
+ and idempotency APIs as app-auth invocations. The Runtime Store records only token-free request
629
+ state, events, and results. The forwarded credential stays process-local for the active first
630
+ attempt and closes when that attempt completes, fails, or is cancelled. A replacement attempt after
631
+ failure recovery stops with `MCP_USER_AUTH_RECOVERY_UNSUPPORTED` because no user credential is
632
+ available; neither the invoke nor recovery handler runs for that attempt.
633
+
634
+ Before deploying user-auth tools from an older project, migrate its request handler and framework
635
+ adapter to the current request-auth-aware `DurableAgentServer` template, then explicitly choose `user` or
636
+ `app` on **every** managed MCP, sandbox, or Genie entry. Changing `agent.toml` alone does not
637
+ upgrade copied Python adapter code. Outdated adapters fail closed rather than silently using App
638
+ identity. App-only legacy projects and generic bring-your-own source directories keep the existing
639
+ path.
640
+
641
+ Deploy derives Apps user scopes from explicit `auth = "user"` bindings:
642
+
643
+ | Binding | Requested Apps scopes |
644
+ | --- | --- |
645
+ | Managed MCP (governed ingress) | `ai-gateway` |
646
+ | `system.ai.genie_one_mcp` | `ai-gateway`, `genie` |
647
+ | First-class Genie One or Genie Agent | `genie` |
648
+
649
+ For example, bind Genie tools in a current project with `server = "agentbricks"`:
650
+
651
+ ```sh
652
+ ab tools add mcp system.ai.genie_one_mcp --auth user
653
+ ab tools add genie-agent SPACE_ID --auth user
654
+ ```
655
+
656
+ Mixed bindings request the union. App-auth and legacy bindings add no user scopes. These are
657
+ explicit service-consent scopes, not a claim that gateway access alone authorizes the downstream
658
+ resource. OAuth consent does not grant Unity Catalog privileges: the user still needs access to
659
+ the configured Genie Space and its underlying data.
660
+
661
+ For a new App, deploy explicitly enables user-token forwarding and includes these scopes in the
662
+ initial typed SDK create request before uploading source. An existing App that is missing a required
663
+ scope needs one-time explicit permission:
664
+
665
+ ```sh
666
+ ab --profile my-workspace deploy my-agent --allow-user-scope-update
667
+ ```
668
+
669
+ The `system.ai.dbsql` managed MCP additionally requests the Apps `sql` user scope. This is full SQL
670
+ API consent, not `sql:restricted-query`; read-only enforcement remains the service policy plus the
671
+ requesting user's Unity Catalog grants. DBSQL does not use Databricks Connect.
672
+
673
+ A sandbox binding with a Volume downscope additionally requests the Apps `files` user scope.
674
+ OAuth consent does not grant Volume access: the requesting user still needs the corresponding
675
+ Unity Catalog privileges, and the sandbox downscope remains authoritative. Table-only sandbox
676
+ bindings request `ai-gateway` but do not request `files`.
677
+
678
+ Review the target App's scopes and coordinate with its other owners before allowing the update. Once
679
+ those scopes are present, later deploys do not need the flag. The CLI preserves unrelated scopes,
680
+ updates only user scopes and any explicitly requested instance counts, and checks requested **and
681
+ effective** scopes before source rollout. It checks for scope changes since preflight, but Apps
682
+ read/write is **not atomic**; this is not a lock or a compare-and-swap guarantee. Polling is bounded
683
+ and a mismatch stops source deployment.
684
+ Users may need to sign out and **re-consent** after changing scopes; effective-scope verification
685
+ does not refresh an existing user's consent.
686
+
687
+ Apps may report `iam.access-control:read` and `iam.current-user:read` as implicit effective
688
+ scopes. The CLI permits these platform defaults during verification but does not request them
689
+ as configurable scopes. Explicitly disabled user-token forwarding stops deployment; enable
690
+ forwarding and restart the App compute before retrying.
691
+
692
+ Removing a tool or switching back to app-only auth **does not remove Apps scopes**. Remove
693
+ unneeded scopes explicitly in Databricks Apps, and verify both configured and effective scopes
694
+ before declaring removal complete. The CLI does not send empty-list scope updates: the SDK's
695
+ `App.as_dict()` omits empty lists, so that would not prove removal succeeded. No scopes are
696
+ managed for generic bring-your-own apps without this managed user contract.
697
+
698
+ App-auth tools execute with workload privileges. Restrict App `CAN USE` to callers trusted
699
+ for **all** App-auth tools, or deploy those tools separately. Models, custom MCP servers,
700
+ Memory/Session Stores, and tracing keep their existing credentials.
701
+
702
+ For MCP services, the remove command accepts the same service name as the add command. You can also
703
+ remove any binding by its `id` in `agent.toml`, for example `ab tools remove web_search`.
704
+ Every successful add (including an already-configured no-op) points you to the target project's
705
+ `agent.toml` to review configured managed tools and MCP bindings. With `--source`, the message
706
+ points to that project's file. JSON add output includes its path in `manifest`.
707
+
708
+ `ab tools list` discovers **available integrations to add**, not configured bindings. By default
709
+ it shows built-in add recipes and caller-visible MCP Services in `system.ai`. A recipe may still
710
+ need your resources: sandbox scopes, a concrete UC function name, or a Genie Space ID. Genie One
711
+ needs no additional argument. `system.ai.sandbox` is represented by its scoped recipe rather than
712
+ a second unscoped add command. The list does not enumerate every workspace schema, individual
713
+ operations inside MCP services, or custom Python tools.
714
+
715
+ `ab tools add mcp` looks up the service in the selected workspace before writing `agent.toml`.
716
+ Use `ab --profile <profile> tools add mcp <service>` to select a workspace. A missing service or
717
+ failed lookup (including authentication or permission errors) leaves the project unchanged. This
718
+ checks service metadata access, not whether every tool can be executed at runtime. Removing local
719
+ bindings does not require workspace access.
720
+
721
+ ```sh
722
+ ab tools list
723
+ ab tools list --kind mcp
724
+ ab tools list --kind mcp --schema main.tools
725
+ ab tools list --kind sandbox
726
+ ab tools list --kind genie-one
727
+ ab tools list --kind genie-agent
728
+ ab --output json tools list
729
+ ```
730
+
731
+ No agent project is required for discovery. MCP discovery uses your Databricks profile; the
732
+ `sandbox`, `uc-function`, `genie-one`, and `genie-agent` kind filters show local recipes without
733
+ authentication. `--schema` requires `--kind mcp` and replaces the default `system.ai` scope. An
734
+ API/authentication failure returns nonzero and marks discovery incomplete, while retaining local
735
+ recipes; it is not reported as an empty successful discovery. Listing metadata does not verify
736
+ runtime execution permissions.
737
+
738
+ **Migration:** the former configured `tools list` view and its `--source` option are removed.
739
+ Read `agent.toml` (its `[[tools]]` entries) to inspect configured bindings. Discovery JSON uses
740
+ `schema_version: 2`, with `available_tools` (`name`, `kind`, `add_command`), `mcp_schema` (null for
741
+ local-only recipes), `complete`, and `errors`. Replace old scripts that read configured-list JSON
742
+ with TOML inspection. Replace `ab mcp list [--schema catalog.schema]` with
743
+ `ab tools list --kind mcp [--schema catalog.schema]`; the former command is removed. Use
744
+ `ab tools list --help` for the new discovery contract.
745
+
746
+ Read-only live discovery can be checked against the installed wheel without creating a project
747
+ or deploying an agent:
748
+
749
+ ```sh
750
+ AGENTBRICKS_E2E_PROFILE=<profile> .venv-functional/bin/pytest tests/e2e/tool_discovery_test.py -v
751
+ ```
752
+
753
+ The live checks compare default and MCP-filtered discovery with the compatibility service list.
754
+ Set `AGENTBRICKS_E2E_SCHEMA=catalog.schema` to exercise an additional schema. The installed CLI's local
755
+ add/review/remove flows and all updated help pages are covered by `tests/functional/cli_smoke_test.py`.
756
+
757
+ In managed-server templates, custom Python tools are code-first. Write them with the framework's native
758
+ decorator in `agent/tools/`: LangGraph uses `@tool`, while OpenAI Agents uses `@function_tool`. The
759
+ templates auto-discover decorated tools from that package and add them to the agent; there is no CLI
760
+ command or `agent.toml` entry to keep in sync. Customer-managed MCP servers are likewise ordinary
761
+ code in `agent/mcps.py` and are joined with the managed bindings by `mcp_tools(...)` or
762
+ `mcp_servers(...)`.
763
+
764
+ Projects created with `--server custom` do not auto-discover `agent/tools/` or load managed tool
765
+ bindings from `agent.toml`, so `ab tools add` rejects those projects. Wire framework-native Python
766
+ tools and MCP servers directly in `agent/agent.py` instead.
767
+
768
+ If a manifest with `server = "agentbricks"` contains `source = { kind = "python", ... }`, remove that
769
+ `[[tools]]` entry; the decorated tool in `agent/tools/` remains active. `ab dev` and `ab deploy`
770
+ do not generate or patch Python tool code, and do not alter the manifest's `[[tools]]` bindings.
771
+
772
+ Sandbox scopes default to read-only access. Repeat `--scope` to allow more than one resource, use
773
+ `volume:` or `workspace:` for those resource types, and use `--permission read_write` only when the
774
+ agent needs writes. Every sandbox call carries this fixed downscope in MCP `_meta`, outside the tool
775
+ arguments controlled by the model.
776
+
777
+ ### Genie tools
778
+
779
+ Genie One and Genie Agent support ship with Agent Bricks CLI, but bindings are opt-in, like sandbox tools.
780
+ Installing the current `databricks-agentbricks` distribution does not configure a Genie Space ID or enable a Genie binding. Add only the
781
+ capabilities your agent needs:
782
+
783
+ ```sh
784
+ ab tools add genie-one --name genie_one --auth user
785
+ ab tools add genie-agent SPACE_ID --name genie_agent --auth user
786
+ ab tools list --kind genie-one
787
+ ab tools list --kind genie-agent
788
+ ab tools remove genie_one
789
+ ab tools remove genie_agent
790
+ ```
791
+
792
+ `--name` is optional and defaults to `genie_one` or `genie_agent`, respectively. `--auth` defaults
793
+ to `user`; choose `--auth app` deliberately for App service-principal execution. Existing manifests
794
+ without `auth` preserve App/default identity. Both add commands and `remove` accept `--source PATH`
795
+ to select a project instead of the current directory. Discovery needs no project; read that
796
+ project's `agent.toml` to inspect configured bindings. For scripted output, put the global
797
+ `-o json` option before `tools`, as in
798
+ `ab -o json tools add genie-one --source ./my-agent`. Adding a binding is offline: it updates
799
+ `agent.toml` without contacting Genie or checking permissions. The corresponding sources are:
800
+
801
+ ```toml
802
+ [[tools]]
803
+ id = "genie_one"
804
+ auth = "user"
805
+ source = { kind = "genie_one" }
806
+
807
+ [[tools]]
808
+ id = "genie_agent"
809
+ auth = "user"
810
+ source = { kind = "genie_agent", space_id = "<your-space-id>" }
811
+ ```
812
+
813
+ Replace `SPACE_ID` or `<your-space-id>` with an existing space's 32-character lowercase hexadecimal
814
+ ID. `genie-one` connects to the workspace-wide MCP endpoint
815
+ `https://<workspace-hostname>/api/2.0/mcp/genie`, without a space suffix. `genie-agent` uses the
816
+ native Genie **Chat-mode** conversation API through the Databricks SDK, not the streaming
817
+ Agent-mode API or the per-space MCP endpoint.
818
+
819
+ Each native binding exposes `{id}_ask`, `{id}_poll`, and `{id}_query_result`, where `{id}` is its
820
+ binding name. Ask accepts an optional `conversation_id` for follow-ups. Ask and poll share a
821
+ 120-second budget per call, including client setup and submission. If the response is still
822
+ running, they return `timed_out` with the conversation and message IDs so the caller can poll
823
+ again. If submission times out before a message ID is received, ask returns
824
+ `INDETERMINATE_SUBMISSION`: the request may still complete, so do not resubmit automatically.
825
+ `NOT_SUBMITTED` means client setup timed out before sending the question. Query results include
826
+ the first 100 rows, column schema, a truncation indicator, and a deep link to the conversation.
827
+
828
+ Both framework modules, `databricks_agentkit.langgraph` and `databricks_agentkit.openai`, export
829
+ `genie_tools()`. New managed-server templates (`server = "agentbricks"`) use it automatically for native Genie Agent bindings;
830
+ Genie One uses the existing managed MCP helpers. In an existing project with `server = "agentbricks"`, import
831
+ `genie_tools` from your framework module and add `*genie_tools()` to the agent's existing tool list.
832
+ The CLI does not patch existing Python code.
833
+
834
+ Both paths use Databricks authentication and the routed workspace. Genie One requires the
835
+ Managed MCP Servers workspace preview; delegated access requires the `genie` OAuth scope.
836
+ The effective caller needs access to the data, the SQL warehouse, and the selected Genie space
837
+ where applicable. Agent Bricks CLI does not grant permissions or promise a service-principal fallback when
838
+ caller credentials lack access. An offline add succeeding does not establish runtime access.
839
+
840
+ The opt-in live tests exercise both frameworks against the configured workspace and an existing
841
+ Genie space. From `integrations/agentbricks`, with both framework extras installed:
842
+
843
+ ```sh
844
+ DATABRICKS_CONFIG_PROFILE=my-workspace RUN_AGENTBRICKS_GENIE_TESTS=1 \
845
+ AGENTBRICKS_GENIE_SPACE_ID=SPACE_ID \
846
+ uv run pytest tests/integration_tests/genie_tools_test.py
847
+ ```
848
+
849
+ By default they ask for the row count of `samples.nyctaxi.trips`. Set `AGENTBRICKS_GENIE_QUESTION` for
850
+ another dataset and `AGENTBRICKS_GENIE_EXPECTED_VALUE` to assert a known result cell.
851
+
852
+ ## Initialize the chat app demo
853
+
854
+ The chat app is a LangGraph-specific init overlay, not a command that mutates an existing project.
855
+ It is included by default for `--framework langgraph`; pass `--disable-chat-app` to scaffold the
856
+ API-only backend instead.
857
+
858
+ ```sh
859
+ ab init --framework langgraph \
860
+ --profile <profile> \
861
+ ./my-agent
862
+ cd ./my-agent
863
+ ab dev
864
+ ```
865
+
866
+ The chat app includes synchronous, SSE streaming, background polling, Session Store, Memory Store,
867
+ and HITL resume UI. The framework-specific overlay adds `ui/`, `runtime/ui.py`, the UI-enabled
868
+ `runtime/main.py`, and UI tests.
869
+
870
+ For the full deployed demo, bind both managed stores, then deploy:
871
+
872
+ ```sh
873
+ ab sessions bind agent-bricks-demo-sessions
874
+ ab memory bind agent-bricks-demo-memory
875
+ ab --profile <profile> deploy agent-bricks-agent-demo --source .
876
+ ```
877
+
878
+ (`bind` declares the store name in `agent.toml`; `ab deploy` creates any declared-but-missing
879
+ store and grants the app's service principal access to it. The memory store id flows to the runtime
880
+ via the `AGENT_MEMORY_STORE` env var that `deploy` injects; `ab dev` runs locally with memory off
881
+ and does not inject it. The id is not persisted in `agent.toml`.)
882
+
883
+ The chat UI generates a stable application session UUID in browser local storage, places it inside
884
+ the invocation's opaque `input`, and creates a fresh invocation UUID per turn. The
885
+ `__Host-databricks-app-router` cookie remains independent: API clients may reuse it for sticky
886
+ replica routing, but it is neither authentication nor the template's application session state.
887
+
888
+ The generated `README.md` documents every request the client makes: config discovery, sync and SSE
889
+ invocations, background submission and polling, session transcript loading, HITL resume, and memory
890
+ entry operations. Capability colors are automatic from `/api/demo/config`; only the
891
+ sync/streaming/background transport selector is manual.
892
+
893
+ ## Contributing
894
+
895
+ Developing Agent Bricks CLI (`ab`), AgentKit, the runtime, and templates - plus the local dev loop and how to
896
+ test unreleased changes on `ab dev` and `ab deploy`, is covered in
897
+ [CONTRIBUTING.md](CONTRIBUTING.md).