langstitch-sdk 0.1.0__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. langstitch_sdk-0.1.0/.github/workflows/ci.yml +61 -0
  2. langstitch_sdk-0.1.0/.github/workflows/publish.yml +47 -0
  3. langstitch_sdk-0.1.0/.gitignore +9 -0
  4. langstitch_sdk-0.1.0/LICENSE +21 -0
  5. langstitch_sdk-0.1.0/PKG-INFO +396 -0
  6. langstitch_sdk-0.1.0/README.md +348 -0
  7. langstitch_sdk-0.1.0/pyproject.toml +76 -0
  8. langstitch_sdk-0.1.0/src/langstitch/__init__.py +190 -0
  9. langstitch_sdk-0.1.0/src/langstitch/_decorators.py +59 -0
  10. langstitch_sdk-0.1.0/src/langstitch/_version.py +3 -0
  11. langstitch_sdk-0.1.0/src/langstitch/agents.py +60 -0
  12. langstitch_sdk-0.1.0/src/langstitch/app.py +113 -0
  13. langstitch_sdk-0.1.0/src/langstitch/cli.py +181 -0
  14. langstitch_sdk-0.1.0/src/langstitch/config.py +360 -0
  15. langstitch_sdk-0.1.0/src/langstitch/context.py +308 -0
  16. langstitch_sdk-0.1.0/src/langstitch/graph.py +144 -0
  17. langstitch_sdk-0.1.0/src/langstitch/guardrails.py +63 -0
  18. langstitch_sdk-0.1.0/src/langstitch/hitl.py +39 -0
  19. langstitch_sdk-0.1.0/src/langstitch/mcp.py +194 -0
  20. langstitch_sdk-0.1.0/src/langstitch/nodes.py +43 -0
  21. langstitch_sdk-0.1.0/src/langstitch/persona.py +42 -0
  22. langstitch_sdk-0.1.0/src/langstitch/policy.py +44 -0
  23. langstitch_sdk-0.1.0/src/langstitch/providers.py +234 -0
  24. langstitch_sdk-0.1.0/src/langstitch/registries.py +230 -0
  25. langstitch_sdk-0.1.0/src/langstitch/registry.py +302 -0
  26. langstitch_sdk-0.1.0/src/langstitch/scaffold.py +489 -0
  27. langstitch_sdk-0.1.0/src/langstitch/server.py +161 -0
  28. langstitch_sdk-0.1.0/src/langstitch/services.py +450 -0
  29. langstitch_sdk-0.1.0/src/langstitch/skills.py +45 -0
  30. langstitch_sdk-0.1.0/src/langstitch/tools.py +58 -0
  31. langstitch_sdk-0.1.0/src/langstitch/tracing.py +362 -0
  32. langstitch_sdk-0.1.0/tests/conftest.py +14 -0
  33. langstitch_sdk-0.1.0/tests/test_config.py +65 -0
  34. langstitch_sdk-0.1.0/tests/test_config_json.py +87 -0
  35. langstitch_sdk-0.1.0/tests/test_context.py +126 -0
  36. langstitch_sdk-0.1.0/tests/test_decorators.py +82 -0
  37. langstitch_sdk-0.1.0/tests/test_http_client.py +125 -0
  38. langstitch_sdk-0.1.0/tests/test_mcp.py +72 -0
  39. langstitch_sdk-0.1.0/tests/test_properties.py +75 -0
  40. langstitch_sdk-0.1.0/tests/test_providers.py +68 -0
  41. langstitch_sdk-0.1.0/tests/test_registries.py +79 -0
  42. langstitch_sdk-0.1.0/tests/test_scaffold_cli.py +55 -0
  43. langstitch_sdk-0.1.0/tests/test_services.py +175 -0
  44. langstitch_sdk-0.1.0/tests/test_tracing.py +121 -0
@@ -0,0 +1,61 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ['3.10', '3.11', '3.12', '3.13']
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - uses: actions/setup-python@v5
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+
26
+ - name: Install package (with extras)
27
+ run: python -m pip install --upgrade pip && pip install -e ".[dev,http,tracing]"
28
+
29
+ - name: Run tests
30
+ run: python -m pytest -q
31
+
32
+ build:
33
+ runs-on: ubuntu-latest
34
+ needs: test
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+
38
+ - uses: actions/setup-python@v5
39
+ with:
40
+ python-version: '3.12'
41
+
42
+ - name: Install build tooling
43
+ run: python -m pip install --upgrade pip build twine
44
+
45
+ - name: Build sdist + wheel
46
+ run: python -m build
47
+
48
+ - name: Validate distribution metadata
49
+ run: python -m twine check dist/*
50
+
51
+ - name: Verify wheel installs and CLI runs
52
+ run: |
53
+ python -m venv /tmp/venv
54
+ /tmp/venv/bin/pip install dist/*.whl
55
+ /tmp/venv/bin/langstitch version
56
+
57
+ - name: Upload distribution artifacts
58
+ uses: actions/upload-artifact@v4
59
+ with:
60
+ name: langstitch-dist
61
+ path: dist/*
@@ -0,0 +1,47 @@
1
+ name: Publish
2
+
3
+ # Publishes the langstitch SDK to PyPI when a tag like `v0.1.0` is pushed (or a
4
+ # matching GitHub Release is published). Uses PyPI Trusted Publishing (OIDC) —
5
+ # no API token secret required once the project is configured on PyPI to trust
6
+ # this workflow.
7
+
8
+ on:
9
+ push:
10
+ tags:
11
+ - 'v*'
12
+ release:
13
+ types: [published]
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ build:
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: actions/setup-python@v5
24
+ with:
25
+ python-version: '3.12'
26
+ - name: Build distribution
27
+ run: python -m pip install --upgrade pip build twine && python -m build && python -m twine check dist/*
28
+ - uses: actions/upload-artifact@v4
29
+ with:
30
+ name: langstitch-dist
31
+ path: dist/*
32
+
33
+ publish:
34
+ needs: build
35
+ runs-on: ubuntu-latest
36
+ environment: pypi
37
+ permissions:
38
+ id-token: write # required for PyPI Trusted Publishing
39
+ steps:
40
+ - uses: actions/download-artifact@v4
41
+ with:
42
+ name: langstitch-dist
43
+ path: dist
44
+ - name: Publish to PyPI
45
+ uses: pypa/gh-action-pypi-publish@release/v1
46
+ with:
47
+ packages-dir: dist
@@ -0,0 +1,9 @@
1
+ dist/
2
+ build/
3
+ *.egg-info/
4
+ .eggs/
5
+ __pycache__/
6
+ *.py[cod]
7
+ .pytest_cache/
8
+ .venv/
9
+ venv/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LangStitch
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,396 @@
1
+ Metadata-Version: 2.4
2
+ Name: langstitch-sdk
3
+ Version: 0.1.0
4
+ Summary: LangStitch SDK — decorators, config, and CLI for building LangGraph applications with a clean project scaffold.
5
+ Project-URL: Homepage, https://langstitch.com
6
+ Project-URL: Documentation, https://langstitch.com/docs/
7
+ Project-URL: Repository, https://github.com/LangStitch/langstitch-sdk
8
+ Author-email: LangStitch <connect@langstitch.com>
9
+ Maintainer-email: LangStitch <connect@langstitch.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agents,langchain,langgraph,langstitch,llm,sdk
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: pyyaml>=6.0
25
+ Provides-Extra: all
26
+ Requires-Dist: fastapi>=0.115.0; extra == 'all'
27
+ Requires-Dist: httpx>=0.27.0; extra == 'all'
28
+ Requires-Dist: langchain-core>=0.3.0; extra == 'all'
29
+ Requires-Dist: langchain>=0.3.0; extra == 'all'
30
+ Requires-Dist: langgraph>=0.4.0; extra == 'all'
31
+ Requires-Dist: langsmith>=0.1.0; extra == 'all'
32
+ Requires-Dist: uvicorn[standard]>=0.32.0; extra == 'all'
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=8.0; extra == 'dev'
35
+ Provides-Extra: graph
36
+ Requires-Dist: langchain-core>=0.3.0; extra == 'graph'
37
+ Requires-Dist: langgraph>=0.4.0; extra == 'graph'
38
+ Provides-Extra: http
39
+ Requires-Dist: httpx>=0.27.0; extra == 'http'
40
+ Provides-Extra: llm
41
+ Requires-Dist: langchain>=0.3.0; extra == 'llm'
42
+ Provides-Extra: server
43
+ Requires-Dist: fastapi>=0.115.0; extra == 'server'
44
+ Requires-Dist: uvicorn[standard]>=0.32.0; extra == 'server'
45
+ Provides-Extra: tracing
46
+ Requires-Dist: langsmith>=0.1.0; extra == 'tracing'
47
+ Description-Content-Type: text/markdown
48
+
49
+ # LangStitch SDK
50
+
51
+ A small, batteries-included Python SDK for building LangGraph applications with a
52
+ clean, conventional project structure. You describe components with decorators,
53
+ configure the app with YAML, and run it with one command.
54
+
55
+ ```bash
56
+ pip install langstitch-sdk # core (PyYAML only)
57
+ pip install "langstitch-sdk[all]" # + FastAPI server + LangGraph
58
+ ```
59
+
60
+ > **Prefer a visual workflow?** The LangStitch IDE ships an **SDK Component Designer** for
61
+ > authoring custom nodes, connectors, and adaptors without writing registration code — define
62
+ > ports, a typed config schema, and a safe Python codegen template, then export the component as
63
+ > a portable `.component.json` or publish it to the
64
+ > [marketplace](https://marketplace.langstitch.com). See the
65
+ > [Component Designer docs](https://langstitch.com/docs/#components). This README covers the
66
+ > **code-first Python SDK**.
67
+
68
+ ### Use it as a dependency
69
+
70
+ In your `pyproject.toml`:
71
+
72
+ ```toml
73
+ [project]
74
+ dependencies = [
75
+ "langstitch-sdk>=0.1.0", # from PyPI
76
+ # extras: "langstitch-sdk[server,graph,llm,http]>=0.1.0"
77
+ ]
78
+ ```
79
+
80
+ Declare it in your `pyproject.toml`:
81
+
82
+ ```toml
83
+ [project]
84
+ dependencies = [
85
+ "langstitch-sdk>=0.1.0",
86
+ ]
87
+ ```
88
+
89
+ ## Quick start
90
+
91
+ ```bash
92
+ langstitch new my-agent
93
+ cd my-agent
94
+ pip install -e .
95
+ python -m app # bootstrap + print app info
96
+ langstitch run # start the API server
97
+ ```
98
+
99
+ ## Decorators
100
+
101
+ | Decorator | Purpose |
102
+ | --- | --- |
103
+ | `@graph_node` | Register a node handler (`state -> dict`). |
104
+ | `@graph` | Register a graph builder (`entrypoint=True` for the root, `parent=...` for subgraphs). |
105
+ | `@skill` | Register a reusable capability. |
106
+ | `@input_guardrail` / `@output_guardrail` | Validate inbound requests / outbound responses. |
107
+ | `@business_policy` | Register an organizational rule (evaluated by `priority`). |
108
+ | `@persona` | Register an agent identity / system prompt. |
109
+ | `@configuration` | Bind a section of `application.yaml` to a dataclass. |
110
+ | `@langstitch_graph_server` | Turn a class into a runnable graph API server (`protocol`, `port`, `name`, `properties`). |
111
+ | `@tool` | Register a callable an LLM can invoke (`roles`, `tags`, `input_schema`). |
112
+ | `@worker_agent` | Register a delegatable sub-agent (`role`, `tools`, `persona`). |
113
+ | `@langstitch_mcp_server` | Mark the MCP server class + transport (`protocol="stdio"\|"sse"\|"streamable-http"\|"http"\|"websocket"`, `properties`). |
114
+ | `@mcp_tool` | Expose a callable as an MCP tool (`name`, `roles`, `description`). |
115
+ | `@mcp_resource` | Expose a readable MCP resource (`name`, `uri`, `mime_type`). |
116
+ | `@mcp_prompt` | Expose a reusable MCP prompt (`name`, `description`, `arguments`). |
117
+
118
+ Every decorator works bare or parameterized:
119
+
120
+ ```python
121
+ from langstitch import skill
122
+
123
+ @skill
124
+ def echo(text: str) -> str:
125
+ return text
126
+
127
+ @skill(name="search", tools=["web"], tags=["retrieval"])
128
+ def web_search(query: str) -> list[str]:
129
+ ...
130
+ ```
131
+
132
+ ## Configuration
133
+
134
+ Two YAML files at the project root drive an app:
135
+
136
+ - **`application.yaml`** — application configuration (app metadata, model, graph, server, custom sections).
137
+ - **`env.yaml`** — runtime environment variables, exported into `os.environ` (existing values win unless `override=True`). Nested keys flatten to `UPPER_SNAKE` (`openai.api_key` → `OPENAI_API_KEY`).
138
+
139
+ ```python
140
+ from langstitch import load_config
141
+
142
+ cfg = load_config() # loads env.yaml then application config
143
+ print(cfg.name, cfg.get("server.port"))
144
+ ```
145
+
146
+ ### Precompiled in-memory config + JSON-path lookups
147
+
148
+ At startup `load_config()` parses the application config **once** into an
149
+ in-memory object (the runtime store). Use `get_config(path)` to read from it
150
+ with a JSON-path-lite syntax (dotted keys, `[index]`, optional leading `$`):
151
+
152
+ ```python
153
+ from langstitch import get_config
154
+
155
+ get_config() # the whole AppConfig
156
+ get_config("server.port") # -> 9001 (scalar)
157
+ get_config("model") # -> {...} (nested object)
158
+ get_config("external_services.payments.auth.type")
159
+ get_config("items[0].name") # array index
160
+ get_config("missing.key", default="fallback")
161
+ get_config("server", as_json=True) # -> '{"host": ...}' (JSON string)
162
+ ```
163
+
164
+ If you keep the config as **`application.json`** it's loaded directly (no
165
+ YAML→JSON conversion) and `application.json` takes precedence over
166
+ `application.yaml`. Precompile once for fast startup:
167
+
168
+ ```bash
169
+ langstitch compile # application.yaml -> application.json
170
+ langstitch get server.port # resolve a path from the CLI
171
+ ```
172
+
173
+ Both server decorators accept `properties=` to pin the config file loaded at
174
+ startup (relative to the project root, or absolute). When omitted, discovery is
175
+ used (`application.json` preferred, else `application.yaml`):
176
+
177
+ ```python
178
+ @langstitch_graph_server(name="api", properties="application.yaml") # pin YAML
179
+ class Server: ...
180
+
181
+ @langstitch_mcp_server(protocol="stdio") # default: application.json then yaml
182
+ class MCPServer: ...
183
+ ```
184
+
185
+ ```python
186
+ from dataclasses import dataclass
187
+ from langstitch import configuration
188
+
189
+ @configuration(section="server")
190
+ @dataclass
191
+ class ServerConfig:
192
+ host: str = "0.0.0.0"
193
+ port: int = 8000
194
+
195
+ # after load_config(): ServerConfig._langstitch_instance is populated
196
+ ```
197
+
198
+ ## Base runtime helpers
199
+
200
+ Factory functions that read `application.yaml` / `env.yaml` so app code never
201
+ hand-builds clients:
202
+
203
+ ```python
204
+ from langstitch import (
205
+ get_config, get_env, get_secret, get_logger,
206
+ get_llm_provider, get_http_client, get_async_http_client,
207
+ )
208
+
209
+ cfg = get_config() # cached AppConfig
210
+ log = get_logger(__name__) # level from LOG_LEVEL
211
+ llm = get_llm_provider() # chat model from model: section (needs [llm])
212
+ http = get_http_client() # httpx.Client from http: section (needs [http])
213
+ key = get_secret("openai_api_key") # env lookup with sensible fallbacks
214
+ ```
215
+
216
+ Heavy deps are optional extras: `pip install "langstitch-sdk[llm]"` (LangChain) and
217
+ `pip install "langstitch-sdk[http]"` (httpx). Without them the helpers raise a clear
218
+ install hint. The same helpers are available as methods on `LangStitchApp`
219
+ (`app.get_llm_provider()`, `app.get_http_client()`, ...).
220
+
221
+ ### External services & `get_http_client("<service>")`
222
+
223
+ Declare downstream HTTP services in `application.yaml`:
224
+
225
+ ```yaml
226
+ external_services:
227
+ payments:
228
+ serverUrl: https://api.payments.com # or server_url
229
+ basePath: /v1 # or base_path
230
+ timeout: 30
231
+ propagate_headers: [x-request-id, authorization]
232
+ auth:
233
+ type: bearer # none | basic | bearer | api_key | oauth2
234
+ token: ${PAYMENTS_TOKEN}
235
+ ```
236
+
237
+ ```python
238
+ from langstitch import get_http_client, set_request_headers
239
+
240
+ # In request middleware, record inbound headers once:
241
+ set_request_headers(request.headers)
242
+
243
+ api = get_http_client("payments") # base_url, timeout, auth + propagated headers wired in
244
+ ```
245
+
246
+ The returned `ServiceClient` covers all HTTP verbs with `{path}` templating and
247
+ per-request header/query merging (auth + propagated headers stay applied):
248
+
249
+ ```python
250
+ api.get("/users/{id}", path_params={"id": 7}, params={"expand": "wallet"})
251
+ api.post("/users", json={"name": "Ada"}, headers={"X-Trace": "1"})
252
+ api.put("/users/{id}", path_params={"id": 7}, json={...})
253
+ api.patch("/users/{id}", path_params={"id": 7}, json={...})
254
+ api.delete("/users/{id}", path_params={"id": 7})
255
+ api.request("OPTIONS", "/users")
256
+
257
+ api.set_header("X-Tenant", "acme") # mutate default headers
258
+ api.add_headers({"X-Region": "eu"})
259
+ ```
260
+
261
+ `get_async_http_client("payments")` returns the awaitable `AsyncServiceClient`
262
+ equivalent. Pass `raw=True` to either for the underlying httpx client.
263
+
264
+ Auth types and their options (string values support `${ENV_VAR}` interpolation):
265
+
266
+ | `auth.type` | Options | Effect |
267
+ | --- | --- | --- |
268
+ | `none` | — | no credentials |
269
+ | `basic` | `username`, `password` | `Authorization: Basic <b64>` |
270
+ | `bearer` | `token` | `Authorization: Bearer <token>` |
271
+ | `api_key` | `name` (default `X-API-Key`), `value`, `in` (`header`\|`query`) | header or query param |
272
+ | `oauth2` | `token_url`, `client_id`, `client_secret`, `scope?`, `audience?` | client-credentials; token fetched + cached/refreshed automatically |
273
+
274
+ `propagate_headers` forwards the listed inbound request headers (case-insensitive)
275
+ onto the outbound client. `get_async_http_client("<service>")` is the async variant.
276
+
277
+ ## Dynamic registries & graph-server internal tools
278
+
279
+ Tools and worker agents are **not eagerly loaded** when a request arrives. The
280
+ registries hold cheap *specs* and refresh themselves automatically when anything
281
+ new registers (and on demand via `refresh_registries()`); the actual callables
282
+ are materialized only when a node selects them.
283
+
284
+ The graph server exposes introspection helpers (each hits the live registries):
285
+
286
+ ```python
287
+ Server.get_all_tools() # [ToolSpec, ...]
288
+ Server.get_all_worker_agents() # [AgentSpec, ...]
289
+ Server.get_input_guardrails()
290
+ Server.get_output_guardrails()
291
+ Server.get_skills(); Server.get_policies(); Server.get_personas()
292
+ Server.get_tool("now"); Server.get_worker_agent("researcher")
293
+ Server.refresh_registries()
294
+ ```
295
+
296
+ The same accessors are module-level functions (`langstitch.get_all_tools()`, ...).
297
+
298
+ ## Hierarchical context (no parent pollution)
299
+
300
+ Every LLM call or sub-agent call runs in a **temporary child context**. The child
301
+ can accumulate tool-call messages and scratch reasoning freely; when the call
302
+ finishes, **only the final output** is merged back into the parent — so parents
303
+ stay small no matter how deep the call tree gets.
304
+
305
+ ```python
306
+ from langstitch import Context, run_llm, run_worker_agent
307
+
308
+ ctx = Context(data={"question": "..."}, messages=[...])
309
+
310
+ def call_model(llm_ctx):
311
+ # llm_ctx.tools were selected (by tag/name/role) and materialized just for
312
+ # this call; llm_ctx.system holds the resolved persona.
313
+ return model.invoke(llm_ctx.messages, tools=llm_ctx.tools)
314
+
315
+ answer = run_llm(ctx, call_model, persona="assistant", tool_tags=["search"], key="answer")
316
+ # ctx.data["answer"] is set; the child's tool traffic + scratch were discarded.
317
+
318
+ # Delegate to a sub-agent (runs with only its allowed tools, isolated context):
319
+ findings = run_worker_agent(ctx, "researcher", carry=["question"])
320
+ ```
321
+
322
+ `ContextBuilder` does the lazy selection; `Context.scope(...)` / `ContextScope`
323
+ give you the raw building blocks if you need finer control.
324
+
325
+ ## Building & running a graph
326
+
327
+ ```python
328
+ from langstitch import LangStitchApp
329
+
330
+ app = LangStitchApp.bootstrap()
331
+ graph = app.build_graph() # compiles to a LangGraph StateGraph
332
+ result = app.invoke({"messages": [{"role": "user", "content": "hi"}]})
333
+ ```
334
+
335
+ ## Tracing, logging & LangSmith
336
+
337
+ Optional observability via `langstitch.tracing` (install `pip install "langstitch-sdk[tracing]"`).
338
+
339
+ ### Configuration
340
+
341
+ ```yaml
342
+ # application.yaml
343
+ tracing:
344
+ enabled: true
345
+ project: my-agent-project
346
+ log_format: json # text | json
347
+ register_on_build: true # upsert LangSmith project on build_graph()
348
+ trace_nodes: true
349
+ ```
350
+
351
+ Environment variables (`LANGSMITH_API_KEY`, `LANGCHAIN_TRACING_V2=true`, `LANGCHAIN_PROJECT`) are applied automatically when tracing is enabled.
352
+
353
+ ### Register a graph with LangSmith
354
+
355
+ ```python
356
+ from langstitch import LangStitchApp, configure_tracing, register_graph
357
+
358
+ configure_tracing()
359
+ app = LangStitchApp.bootstrap()
360
+ app.build_graph() # registers entrypoint when tracing.register_on_build is true
361
+ print(app.info()["registered_graphs"])
362
+ ```
363
+
364
+ CLI:
365
+
366
+ ```bash
367
+ langstitch register # register entrypoint graph (needs app package)
368
+ langstitch register --describe-only # metadata only, no LangGraph compile
369
+ ```
370
+
371
+ ### Runtime agent smoke test
372
+
373
+ The repo ships `runtime/basic_agent.py` — a minimal SDK graph with optional LangSmith registration:
374
+
375
+ ```bash
376
+ python runtime/basic_agent.py
377
+ # {"ok": true, "tracing": {"registered": true, ...}}
378
+ ```
379
+
380
+ ## CLI
381
+
382
+ ```text
383
+ langstitch new <name> [--dir PATH] [--force] scaffold a project
384
+ langstitch info [--root PATH] load config + list components
385
+ langstitch run [--root PATH] [--host] [--port] start the API server
386
+ langstitch register [--root PATH] [--describe-only] LangSmith graph registration
387
+ langstitch compile application.yaml -> application.json
388
+ langstitch get <json.path> resolve config path
389
+ langstitch version
390
+ ```
391
+
392
+ ## Status
393
+
394
+ Phase 1 (initial release): decorators, registry, YAML config, scaffolding CLI,
395
+ and an optional FastAPI server. LangGraph and FastAPI are optional extras so the
396
+ core stays lightweight and importable anywhere (including codegen).