spinekit 0.2.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 (148) hide show
  1. spinekit-0.2.0/.github/PULL_REQUEST_TEMPLATE.md +13 -0
  2. spinekit-0.2.0/.github/workflows/ci.yml +35 -0
  3. spinekit-0.2.0/.github/workflows/docs.yml +39 -0
  4. spinekit-0.2.0/.github/workflows/release.yml +44 -0
  5. spinekit-0.2.0/.gitignore +21 -0
  6. spinekit-0.2.0/.python-version +1 -0
  7. spinekit-0.2.0/.release-please-manifest.json +3 -0
  8. spinekit-0.2.0/CHANGELOG.md +54 -0
  9. spinekit-0.2.0/CODE_OF_CONDUCT.md +57 -0
  10. spinekit-0.2.0/LICENSE +21 -0
  11. spinekit-0.2.0/PKG-INFO +149 -0
  12. spinekit-0.2.0/README.md +89 -0
  13. spinekit-0.2.0/docs/architecture.md +94 -0
  14. spinekit-0.2.0/docs/assets/favicon.svg +8 -0
  15. spinekit-0.2.0/docs/assets/logo-hero.svg +14 -0
  16. spinekit-0.2.0/docs/assets/logo.svg +10 -0
  17. spinekit-0.2.0/docs/concepts/guards.md +48 -0
  18. spinekit-0.2.0/docs/concepts/hitl.md +60 -0
  19. spinekit-0.2.0/docs/concepts/kernel.md +68 -0
  20. spinekit-0.2.0/docs/concepts/middleware.md +67 -0
  21. spinekit-0.2.0/docs/concepts/observability.md +63 -0
  22. spinekit-0.2.0/docs/concepts/providers.md +53 -0
  23. spinekit-0.2.0/docs/concepts/state.md +60 -0
  24. spinekit-0.2.0/docs/concepts/tools.md +72 -0
  25. spinekit-0.2.0/docs/contributing.md +102 -0
  26. spinekit-0.2.0/docs/deepdive/eval.md +121 -0
  27. spinekit-0.2.0/docs/deepdive/mcp.md +100 -0
  28. spinekit-0.2.0/docs/develop/backend.md +92 -0
  29. spinekit-0.2.0/docs/develop/middleware.md +88 -0
  30. spinekit-0.2.0/docs/develop/provider.md +96 -0
  31. spinekit-0.2.0/docs/develop/publish.md +117 -0
  32. spinekit-0.2.0/docs/guides/deployment.md +61 -0
  33. spinekit-0.2.0/docs/guides/eval.md +61 -0
  34. spinekit-0.2.0/docs/guides/examples.md +314 -0
  35. spinekit-0.2.0/docs/guides/guardrails.md +65 -0
  36. spinekit-0.2.0/docs/guides/mcp.md +38 -0
  37. spinekit-0.2.0/docs/guides/memory.md +79 -0
  38. spinekit-0.2.0/docs/guides/models.md +88 -0
  39. spinekit-0.2.0/docs/guides/orchestration.md +52 -0
  40. spinekit-0.2.0/docs/guides/patterns.md +180 -0
  41. spinekit-0.2.0/docs/index.md +57 -0
  42. spinekit-0.2.0/docs/install.md +65 -0
  43. spinekit-0.2.0/docs/quickstart.md +81 -0
  44. spinekit-0.2.0/docs/reference/api.md +123 -0
  45. spinekit-0.2.0/docs/reference/cli.md +156 -0
  46. spinekit-0.2.0/docs/reference/data-model.md +174 -0
  47. spinekit-0.2.0/docs/reference/middleware.md +58 -0
  48. spinekit-0.2.0/docs/reference/plugins.md +70 -0
  49. spinekit-0.2.0/docs/stylesheets/extra.css +133 -0
  50. spinekit-0.2.0/mkdocs.yml +136 -0
  51. spinekit-0.2.0/overrides/home.html +42 -0
  52. spinekit-0.2.0/packages/spine-a2a/src/spine_a2a/__init__.py +17 -0
  53. spinekit-0.2.0/packages/spine-a2a/src/spine_a2a/client.py +101 -0
  54. spinekit-0.2.0/packages/spine-a2a/src/spine_a2a/py.typed +0 -0
  55. spinekit-0.2.0/packages/spine-a2a/tests/test_a2a.py +74 -0
  56. spinekit-0.2.0/packages/spine-backends/src/spine_backends/__init__.py +27 -0
  57. spinekit-0.2.0/packages/spine-backends/src/spine_backends/embeddings.py +68 -0
  58. spinekit-0.2.0/packages/spine-backends/src/spine_backends/memory.py +99 -0
  59. spinekit-0.2.0/packages/spine-backends/src/spine_backends/migrations.py +39 -0
  60. spinekit-0.2.0/packages/spine-backends/src/spine_backends/pgvector.py +140 -0
  61. spinekit-0.2.0/packages/spine-backends/src/spine_backends/postgres.py +85 -0
  62. spinekit-0.2.0/packages/spine-backends/src/spine_backends/py.typed +0 -0
  63. spinekit-0.2.0/packages/spine-backends/src/spine_backends/redis.py +58 -0
  64. spinekit-0.2.0/packages/spine-backends/src/spine_backends/sqlite.py +103 -0
  65. spinekit-0.2.0/packages/spine-backends/tests/test_conformance.py +76 -0
  66. spinekit-0.2.0/packages/spine-backends/tests/test_memory.py +88 -0
  67. spinekit-0.2.0/packages/spine-backends/tests/test_sqlite.py +75 -0
  68. spinekit-0.2.0/packages/spine-cli/src/spine_cli/__init__.py +5 -0
  69. spinekit-0.2.0/packages/spine-cli/src/spine_cli/app.py +363 -0
  70. spinekit-0.2.0/packages/spine-cli/src/spine_cli/builder.py +86 -0
  71. spinekit-0.2.0/packages/spine-cli/src/spine_cli/config.py +92 -0
  72. spinekit-0.2.0/packages/spine-cli/src/spine_cli/plugins.py +54 -0
  73. spinekit-0.2.0/packages/spine-cli/src/spine_cli/py.typed +0 -0
  74. spinekit-0.2.0/packages/spine-cli/src/spine_cli/templates.py +122 -0
  75. spinekit-0.2.0/packages/spine-cli/tests/test_cli.py +204 -0
  76. spinekit-0.2.0/packages/spine-core/src/spine_core/__init__.py +117 -0
  77. spinekit-0.2.0/packages/spine-core/src/spine_core/agent.py +540 -0
  78. spinekit-0.2.0/packages/spine-core/src/spine_core/checkpoint.py +39 -0
  79. spinekit-0.2.0/packages/spine-core/src/spine_core/control.py +25 -0
  80. spinekit-0.2.0/packages/spine-core/src/spine_core/errors.py +23 -0
  81. spinekit-0.2.0/packages/spine-core/src/spine_core/guards.py +45 -0
  82. spinekit-0.2.0/packages/spine-core/src/spine_core/interrupt.py +24 -0
  83. spinekit-0.2.0/packages/spine-core/src/spine_core/memory.py +48 -0
  84. spinekit-0.2.0/packages/spine-core/src/spine_core/messages.py +123 -0
  85. spinekit-0.2.0/packages/spine-core/src/spine_core/middleware.py +157 -0
  86. spinekit-0.2.0/packages/spine-core/src/spine_core/provider.py +103 -0
  87. spinekit-0.2.0/packages/spine-core/src/spine_core/py.typed +0 -0
  88. spinekit-0.2.0/packages/spine-core/src/spine_core/registry.py +76 -0
  89. spinekit-0.2.0/packages/spine-core/src/spine_core/result.py +55 -0
  90. spinekit-0.2.0/packages/spine-core/src/spine_core/state.py +58 -0
  91. spinekit-0.2.0/packages/spine-core/src/spine_core/testing.py +87 -0
  92. spinekit-0.2.0/packages/spine-core/src/spine_core/tools.py +147 -0
  93. spinekit-0.2.0/packages/spine-core/src/spine_core/trace.py +59 -0
  94. spinekit-0.2.0/packages/spine-core/tests/test_hitl.py +102 -0
  95. spinekit-0.2.0/packages/spine-core/tests/test_kernel.py +269 -0
  96. spinekit-0.2.0/packages/spine-core/tests/test_state.py +79 -0
  97. spinekit-0.2.0/packages/spine-eval/src/spine_eval/__init__.py +42 -0
  98. spinekit-0.2.0/packages/spine-eval/src/spine_eval/loader.py +37 -0
  99. spinekit-0.2.0/packages/spine-eval/src/spine_eval/models.py +120 -0
  100. spinekit-0.2.0/packages/spine-eval/src/spine_eval/py.typed +0 -0
  101. spinekit-0.2.0/packages/spine-eval/src/spine_eval/runner.py +71 -0
  102. spinekit-0.2.0/packages/spine-eval/src/spine_eval/scorers.py +132 -0
  103. spinekit-0.2.0/packages/spine-eval/tests/test_eval.py +165 -0
  104. spinekit-0.2.0/packages/spine-mcp/src/spine_mcp/__init__.py +17 -0
  105. spinekit-0.2.0/packages/spine-mcp/src/spine_mcp/py.typed +0 -0
  106. spinekit-0.2.0/packages/spine-mcp/src/spine_mcp/toolset.py +126 -0
  107. spinekit-0.2.0/packages/spine-mcp/tests/test_mcp.py +89 -0
  108. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/__init__.py +72 -0
  109. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/cache.py +80 -0
  110. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/compaction.py +39 -0
  111. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/cost.py +35 -0
  112. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/fallback.py +30 -0
  113. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/guardrails.py +170 -0
  114. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/loopguard.py +43 -0
  115. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/memory.py +66 -0
  116. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/multitenancy.py +52 -0
  117. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/py.typed +0 -0
  118. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/reliability.py +120 -0
  119. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/replay.py +63 -0
  120. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/retry.py +43 -0
  121. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/sandbox.py +99 -0
  122. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/structured.py +79 -0
  123. spinekit-0.2.0/packages/spine-middleware/src/spine_middleware/tooling.py +43 -0
  124. spinekit-0.2.0/packages/spine-middleware/tests/test_cache.py +73 -0
  125. spinekit-0.2.0/packages/spine-middleware/tests/test_guardrails.py +82 -0
  126. spinekit-0.2.0/packages/spine-middleware/tests/test_memory_recall.py +49 -0
  127. spinekit-0.2.0/packages/spine-middleware/tests/test_middleware.py +130 -0
  128. spinekit-0.2.0/packages/spine-middleware/tests/test_multitenancy.py +48 -0
  129. spinekit-0.2.0/packages/spine-middleware/tests/test_reliability.py +114 -0
  130. spinekit-0.2.0/packages/spine-middleware/tests/test_replay.py +51 -0
  131. spinekit-0.2.0/packages/spine-middleware/tests/test_sandbox.py +45 -0
  132. spinekit-0.2.0/packages/spine-orchestration/src/spine_orchestration/__init__.py +7 -0
  133. spinekit-0.2.0/packages/spine-orchestration/src/spine_orchestration/patterns.py +106 -0
  134. spinekit-0.2.0/packages/spine-orchestration/src/spine_orchestration/py.typed +0 -0
  135. spinekit-0.2.0/packages/spine-orchestration/tests/test_orchestration.py +68 -0
  136. spinekit-0.2.0/packages/spine-otel/src/spine_otel/__init__.py +15 -0
  137. spinekit-0.2.0/packages/spine-otel/src/spine_otel/middleware.py +150 -0
  138. spinekit-0.2.0/packages/spine-otel/src/spine_otel/py.typed +0 -0
  139. spinekit-0.2.0/packages/spine-otel/tests/test_otel.py +111 -0
  140. spinekit-0.2.0/packages/spine-providers/src/spine_providers/__init__.py +15 -0
  141. spinekit-0.2.0/packages/spine-providers/src/spine_providers/anthropic.py +258 -0
  142. spinekit-0.2.0/packages/spine-providers/src/spine_providers/openai.py +273 -0
  143. spinekit-0.2.0/packages/spine-providers/src/spine_providers/py.typed +0 -0
  144. spinekit-0.2.0/packages/spine-providers/tests/test_anthropic.py +179 -0
  145. spinekit-0.2.0/packages/spine-providers/tests/test_openai.py +171 -0
  146. spinekit-0.2.0/pyproject.toml +165 -0
  147. spinekit-0.2.0/release-please-config.json +22 -0
  148. spinekit-0.2.0/uv.lock +1918 -0
@@ -0,0 +1,13 @@
1
+ <!-- Thanks for contributing to Spine! -->
2
+
3
+ ## What & why
4
+
5
+ <!-- What does this change, and why? Link any issue. -->
6
+
7
+ ## Checklist
8
+
9
+ - [ ] Gates pass locally: `uv run pytest && uv run ruff check . && uv run ruff format --check . && uv run mypy`
10
+ - [ ] Added/updated tests (no network — use `ScriptedProvider` / fakes)
11
+ - [ ] New feature is a **middleware / backend / adapter**, not a kernel edit
12
+ - [ ] Updated docs / package `README.md` if behavior changed
13
+ - [ ] Conventional commit message (`feat:`, `fix:`, `docs:`, …)
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ gates:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Install uv
15
+ uses: astral-sh/setup-uv@v5
16
+ with:
17
+ enable-cache: true
18
+
19
+ - name: Sync workspace
20
+ run: uv sync
21
+
22
+ - name: Lint (ruff)
23
+ run: uv run ruff check .
24
+
25
+ - name: Format check (ruff)
26
+ run: uv run ruff format --check .
27
+
28
+ - name: Type check (mypy --strict)
29
+ run: uv run mypy
30
+
31
+ - name: Tests
32
+ run: uv run pytest
33
+
34
+ - name: Docs build (strict)
35
+ run: uv run mkdocs build --strict
@@ -0,0 +1,39 @@
1
+ name: Docs
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: pages
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ - uses: astral-sh/setup-uv@v5
23
+ with:
24
+ enable-cache: true
25
+ - run: uv sync
26
+ - run: uv run mkdocs build --strict
27
+ - uses: actions/upload-pages-artifact@v3
28
+ with:
29
+ path: site
30
+
31
+ deploy:
32
+ needs: build
33
+ runs-on: ubuntu-latest
34
+ environment:
35
+ name: github-pages
36
+ url: ${{ steps.deployment.outputs.page_url }}
37
+ steps:
38
+ - id: deployment
39
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,44 @@
1
+ name: Release
2
+
3
+ # release-please opens/maintains a "Release PR" as commits land on main.
4
+ # Merging that PR bumps the version, updates CHANGELOG.md, and creates the
5
+ # GitHub release + tag — which, in the SAME run, publishes to PyPI via OIDC.
6
+ on:
7
+ push:
8
+ branches: [main]
9
+
10
+ permissions: {}
11
+
12
+ jobs:
13
+ release-please:
14
+ runs-on: ubuntu-latest
15
+ permissions:
16
+ contents: write
17
+ pull-requests: write
18
+ outputs:
19
+ release_created: ${{ steps.rp.outputs.release_created }}
20
+ tag_name: ${{ steps.rp.outputs.tag_name }}
21
+ steps:
22
+ - id: rp
23
+ uses: googleapis/release-please-action@v4
24
+ with:
25
+ token: ${{ secrets.GITHUB_TOKEN }}
26
+
27
+ publish:
28
+ needs: release-please
29
+ if: ${{ needs.release-please.outputs.release_created == 'true' }}
30
+ runs-on: ubuntu-latest
31
+ permissions:
32
+ id-token: write # OIDC trusted publishing — no stored secret
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: astral-sh/setup-uv@v5
36
+ with:
37
+ enable-cache: true
38
+ - name: Build the spinekit distribution
39
+ run: |
40
+ rm -rf dist
41
+ uv build --out-dir dist
42
+ ls -la dist
43
+ - name: Publish to PyPI
44
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,21 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Docs build output
13
+ /site/
14
+
15
+ # Tooling caches
16
+ .hypothesis/
17
+ .pytest_cache/
18
+ .ruff_cache/
19
+ .mypy_cache/
20
+ .coverage
21
+ htmlcov/
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.2.0"
3
+ }
@@ -0,0 +1,54 @@
1
+ # Changelog
2
+
3
+ ## [0.2.0](https://github.com/Research-Analytics-Solutions/spine/compare/v0.1.0...v0.2.0) (2026-06-18)
4
+
5
+
6
+ ### Features
7
+
8
+ * **a2a:** agent-to-agent adapter — call a remote agent as a tool ([473bdfe](https://github.com/Research-Analytics-Solutions/spine/commit/473bdfe9803dd722a27a7624ab71b64e3a2d3550))
9
+ * **backends:** Redis + Postgres checkpoint backends + conformance suite ([a9d8990](https://github.com/Research-Analytics-Solutions/spine/commit/a9d8990e41e8f6383dc26c1f11524de2ba9b89c9))
10
+ * **backends:** spine-backends with durable SQLite checkpoint ([9974652](https://github.com/Research-Analytics-Solutions/spine/commit/997465223cb3c3d7d01d3ace2eda755bfc01a1e2))
11
+ * **cli:** config-driven agent build + chat/trace commands ([8da432e](https://github.com/Research-Analytics-Solutions/spine/commit/8da432e3157e7e26861e5c01e8814f4e67c79423))
12
+ * **cli:** spine dev — live-streaming trace viewer ([5b2ed12](https://github.com/Research-Analytics-Solutions/spine/commit/5b2ed127d9520a364ee54b21f52f9a77d24c63d1))
13
+ * **cli:** spine-cli with init/run/doctor/plugin (Typer + Rich) ([422d1b5](https://github.com/Research-Analytics-Solutions/spine/commit/422d1b579c3f810e93b8f4a96f246ef29d1d77f6))
14
+ * **core:** parallel tool calls, cooperative cancellation, sub-agents ([14ce08f](https://github.com/Research-Analytics-Solutions/spine/commit/14ce08f1d32f72c3d71e0cf3db495e20408b376c))
15
+ * **core:** spine-core kernel — loop, guards, middleware, tools, HITL ([450df11](https://github.com/Research-Analytics-Solutions/spine/commit/450df1135b10b8fe5032b217eb75fba93fa9c9ca))
16
+ * **eval:** spine-eval harness + spine eval CLI command ([316c27b](https://github.com/Research-Analytics-Solutions/spine/commit/316c27bb6c1ee849bab4767c52907f404393c716))
17
+ * **mcp:** spine-mcp adapter + raw_tool core primitive ([80676fb](https://github.com/Research-Analytics-Solutions/spine/commit/80676fb403ba607b29d1e52f3b1d8317418ccd5b))
18
+ * **memory:** pluggable embedders + multiple memory types ([7f5a1b8](https://github.com/Research-Analytics-Solutions/spine/commit/7f5a1b8aa6a0649364fc6c776ffb497944835385))
19
+ * **memory:** semantic memory protocol, vector backend, recall middleware ([e59b306](https://github.com/Research-Analytics-Solutions/spine/commit/e59b306a80defc8ea8a8eebc0440d149d9d34f3b))
20
+ * **middleware:** deterministic replay (Recorder/Replayer) ([327c39b](https://github.com/Research-Analytics-Solutions/spine/commit/327c39b458d2af8e6bcaedd87741ec945a39559b))
21
+ * **middleware:** guardrails — PII redaction, injection screening, content policy ([a714367](https://github.com/Research-Analytics-Solutions/spine/commit/a714367e0510648086f28e14b27a8fea9eb311e6))
22
+ * **middleware:** prompt/response Cache + kernel cache-hit short-circuit ([0deab9c](https://github.com/Research-Analytics-Solutions/spine/commit/0deab9c55a9c44764b0744d4bf1cc225e0624501))
23
+ * **middleware:** tool timeout/truncation, circuit breaker, idempotency, rate limit ([de4e27a](https://github.com/Research-Analytics-Solutions/spine/commit/de4e27a7b8c03a5a91966182c810ffbe40f655e2))
24
+ * **middleware:** V1 middleware suite + kernel control primitives ([a6d7766](https://github.com/Research-Analytics-Solutions/spine/commit/a6d776663bdb644d5e24d7f28a8bd225c28d8617))
25
+ * **multimodal:** image/file content parts on Message + provider mapping ([4993441](https://github.com/Research-Analytics-Solutions/spine/commit/4993441cb2f3accf475a216e15c60ed1cc51f896))
26
+ * **multitenancy:** tenant_id on state + per-tenant budget guard ([b306e11](https://github.com/Research-Analytics-Solutions/spine/commit/b306e11a65323ea736fe24f07585150973906458))
27
+ * **orchestration:** sequential, supervisor, handoff patterns ([d2adb2e](https://github.com/Research-Analytics-Solutions/spine/commit/d2adb2eceb769e5dc5c7f73f8917adc2fdb382f4))
28
+ * **otel:** spine-otel — one OpenTelemetry span tree per run ([2453bf2](https://github.com/Research-Analytics-Solutions/spine/commit/2453bf2f8383389b022d2b838cf143ab497fe160))
29
+ * **providers:** add OpenAI adapter ([6005eb9](https://github.com/Research-Analytics-Solutions/spine/commit/6005eb955a8a313fa1ce5af9e96bf7d438342f9a))
30
+ * **providers:** spine-providers with Anthropic adapter ([cbe1171](https://github.com/Research-Analytics-Solutions/spine/commit/cbe1171a53a139fc51dec356ec3adf89189f2a1c))
31
+ * **sandbox:** resource-limited subprocess sandbox for sync tools ([5622d1a](https://github.com/Research-Analytics-Solutions/spine/commit/5622d1a4dfc0266fae16357a6de33919384bccef))
32
+ * **streaming:** token-level streaming through provider + kernel ([85df88a](https://github.com/Research-Analytics-Solutions/spine/commit/85df88aff07f9672d1d8e06e2d309422f243dea7))
33
+
34
+
35
+ ### Bug Fixes
36
+
37
+ * **core:** auto-resolve provider scheme via plugin entry points ([4f2213d](https://github.com/Research-Analytics-Solutions/spine/commit/4f2213d419393153d62703495f691932168cb98c))
38
+ * **core:** bound provider-retry loop; make resume token durable ([1b6c434](https://github.com/Research-Analytics-Solutions/spine/commit/1b6c434c15e74864c734ebd387df50da3383e32d))
39
+
40
+
41
+ ### Documentation
42
+
43
+ * contributor guide, plugin development & publishing, eval/MCP deep dives ([81b126f](https://github.com/Research-Analytics-Solutions/spine/commit/81b126f4cdbdc5fa02a8de5ea4a399b9bdddfbc4))
44
+ * deep reference — data model, cookbook, patterns, expanded CLI & API ([409701a](https://github.com/Research-Analytics-Solutions/spine/commit/409701a834202fdc5aef938814bc6ae7c66cc16f))
45
+ * fix mermaid diagram invisibility in dark mode ([359985d](https://github.com/Research-Analytics-Solutions/spine/commit/359985ddde0d6fe42c8f4824f55b43c4d2b67b3b))
46
+ * landing page hero, logo, mermaid + grid-card fixes ([13f929b](https://github.com/Research-Analytics-Solutions/spine/commit/13f929b05ddeae0f54eaee1c6d4cefe1adb38c1f))
47
+ * mkdocs-material documentation site ([4e63082](https://github.com/Research-Analytics-Solutions/spine/commit/4e630824e14303896c3d0c2e0254654f9d6bb4d2))
48
+ * reconcile with single spinekit distribution ([878a934](https://github.com/Research-Analytics-Solutions/spine/commit/878a934cfbc2611b62edadfde1d090bb6f0e69ef))
49
+ * replace ASCII four-planes box with a styled mermaid diagram ([86c3de3](https://github.com/Research-Analytics-Solutions/spine/commit/86c3de382c21bc0b53b860c5be504fabeda66ecb))
50
+
51
+
52
+ ### Build & Packaging
53
+
54
+ * repackage as a single 'spinekit' distribution with extras ([a4e3765](https://github.com/Research-Analytics-Solutions/spine/commit/a4e37655c38751990134a3b6cbb62e584c31d5f1))
@@ -0,0 +1,57 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment:
18
+
19
+ - Demonstrating empathy and kindness toward other people
20
+ - Being respectful of differing opinions, viewpoints, and experiences
21
+ - Giving and gracefully accepting constructive feedback
22
+ - Accepting responsibility and apologizing to those affected by our mistakes
23
+ - Focusing on what is best for the overall community
24
+
25
+ Examples of unacceptable behavior:
26
+
27
+ - The use of sexualized language or imagery, and sexual attention or advances
28
+ - Trolling, insulting or derogatory comments, and personal or political attacks
29
+ - Public or private harassment
30
+ - Publishing others' private information without explicit permission
31
+ - Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Enforcement Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying and enforcing our standards
37
+ and will take appropriate and fair corrective action in response to any behavior
38
+ that they deem inappropriate, threatening, offensive, or harmful.
39
+
40
+ ## Scope
41
+
42
+ This Code of Conduct applies within all community spaces, and also applies when
43
+ an individual is officially representing the community in public spaces.
44
+
45
+ ## Enforcement
46
+
47
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
48
+ reported to the project maintainers responsible for enforcement. All complaints
49
+ will be reviewed and investigated promptly and fairly.
50
+
51
+ ## Attribution
52
+
53
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
54
+ version 2.1, available at
55
+ <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
56
+
57
+ [homepage]: https://www.contributor-covenant.org
spinekit-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Research Analytics Solutions
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,149 @@
1
+ Metadata-Version: 2.4
2
+ Name: spinekit
3
+ Version: 0.2.0
4
+ Summary: A lightweight, modular, protocol-native runtime for production AI agents.
5
+ Project-URL: Homepage, https://github.com/Research-Analytics-Solutions/spine
6
+ Project-URL: Documentation, https://research-analytics-solutions.github.io/spine/
7
+ Project-URL: Repository, https://github.com/Research-Analytics-Solutions/spine
8
+ Author: Research Analytics Solutions
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: a2a,agents,ai,kernel,llm,mcp,runtime
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Requires-Python: >=3.12
19
+ Requires-Dist: anyio>=4.4
20
+ Requires-Dist: pydantic>=2.7
21
+ Provides-Extra: a2a
22
+ Requires-Dist: httpx>=0.27; extra == 'a2a'
23
+ Provides-Extra: all
24
+ Requires-Dist: anthropic>=0.40; extra == 'all'
25
+ Requires-Dist: asyncpg>=0.29; extra == 'all'
26
+ Requires-Dist: httpx>=0.27; extra == 'all'
27
+ Requires-Dist: mcp>=1.2; extra == 'all'
28
+ Requires-Dist: openai>=1.40; extra == 'all'
29
+ Requires-Dist: opentelemetry-api>=1.27; extra == 'all'
30
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27; extra == 'all'
31
+ Requires-Dist: opentelemetry-sdk>=1.27; extra == 'all'
32
+ Requires-Dist: pyyaml>=6.0; extra == 'all'
33
+ Requires-Dist: redis>=5.0; extra == 'all'
34
+ Requires-Dist: rich>=13.7; extra == 'all'
35
+ Requires-Dist: typer>=0.12; extra == 'all'
36
+ Provides-Extra: anthropic
37
+ Requires-Dist: anthropic>=0.40; extra == 'anthropic'
38
+ Provides-Extra: cli
39
+ Requires-Dist: rich>=13.7; extra == 'cli'
40
+ Requires-Dist: typer>=0.12; extra == 'cli'
41
+ Provides-Extra: eval
42
+ Requires-Dist: pyyaml>=6.0; extra == 'eval'
43
+ Provides-Extra: mcp
44
+ Requires-Dist: mcp>=1.2; extra == 'mcp'
45
+ Provides-Extra: openai
46
+ Requires-Dist: openai>=1.40; extra == 'openai'
47
+ Provides-Extra: otel
48
+ Requires-Dist: opentelemetry-api>=1.27; extra == 'otel'
49
+ Requires-Dist: opentelemetry-sdk>=1.27; extra == 'otel'
50
+ Provides-Extra: otlp
51
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27; extra == 'otlp'
52
+ Provides-Extra: postgres
53
+ Requires-Dist: asyncpg>=0.29; extra == 'postgres'
54
+ Provides-Extra: providers
55
+ Requires-Dist: anthropic>=0.40; extra == 'providers'
56
+ Requires-Dist: openai>=1.40; extra == 'providers'
57
+ Provides-Extra: redis
58
+ Requires-Dist: redis>=5.0; extra == 'redis'
59
+ Description-Content-Type: text/markdown
60
+
61
+ <p align="center">
62
+ <img src="docs/assets/logo-hero.svg" alt="Spine" width="110" />
63
+ </p>
64
+
65
+ <h1 align="center">Spine</h1>
66
+
67
+ <p align="center">
68
+ <strong>A lightweight, modular, protocol-native runtime for production AI agents.</strong>
69
+ </p>
70
+
71
+ <p align="center">
72
+ <a href="https://github.com/Research-Analytics-Solutions/spine/actions/workflows/ci.yml"><img src="https://github.com/Research-Analytics-Solutions/spine/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
73
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
74
+ <img src="https://img.shields.io/badge/python-3.12%2B-blue.svg" alt="Python 3.12+">
75
+ <a href="https://research-analytics-solutions.github.io/spine/"><img src="https://img.shields.io/badge/docs-mkdocs--material-526CFE.svg" alt="Docs"></a>
76
+ </p>
77
+
78
+ <p align="center">
79
+ <a href="https://research-analytics-solutions.github.io/spine/">Documentation</a> ·
80
+ <a href="https://research-analytics-solutions.github.io/spine/quickstart/">Quickstart</a> ·
81
+ <a href="https://research-analytics-solutions.github.io/spine/guides/examples/">Cookbook</a> ·
82
+ <a href="https://research-analytics-solutions.github.io/spine/contributing/">Contributing</a>
83
+ </p>
84
+
85
+ ---
86
+
87
+ Spine is the *kernel* for AI agents — a tiny, load-bearing runtime that everything
88
+ else plugs into. Where monolithic frameworks bundle heavy abstractions, Spine
89
+ ships a small core and pushes every feature into **opt-in middleware, swappable
90
+ backends, and protocol adapters**.
91
+
92
+ ```python
93
+ from spine_core import Agent
94
+
95
+ agent = Agent("openai:gpt-4o-mini")
96
+ print((await agent.run("say hello")).answer)
97
+ ```
98
+
99
+ ## Three guarantees
100
+
101
+ - **No hidden prompts** — every model call consumes inspectable, typed `Message` objects.
102
+ - **No runaway loops** — guards are enforced inside the kernel, every iteration.
103
+ - **Deterministic replay** — any run can be recorded and replayed step-for-step.
104
+
105
+ ## Install
106
+
107
+ One package, lean core, opt-in extras:
108
+
109
+ ```bash
110
+ pip install spinekit # kernel only (pydantic + anyio)
111
+ pip install "spinekit[openai]" # + OpenAI
112
+ pip install "spinekit[anthropic,redis,cli]" # pick parts
113
+ pip install "spinekit[all]" # everything
114
+ ```
115
+
116
+ Import name stays `spine_core`. See the [install guide](https://research-analytics-solutions.github.io/spine/install/).
117
+
118
+ ## What's in the box
119
+
120
+ | Module | Extra | What |
121
+ |---|---|---|
122
+ | `spine_core` | — | the kernel — loop, state, guards, tracer, protocols, HITL, streaming |
123
+ | `spine_middleware` | — | retry, fallback, guardrails, cache, memory recall, sandbox, replay, … |
124
+ | `spine_backends` | `redis` / `postgres` | checkpoints (SQLite always; Redis/Postgres) + memory (vector/buffer/pgvector) |
125
+ | `spine_providers` | `openai` / `anthropic` | OpenAI + Anthropic (and any OpenAI-compatible endpoint) |
126
+ | `spine_mcp` · `spine_a2a` · `spine_otel` | `mcp` · `a2a` · `otel` | MCP tools · remote agents · OpenTelemetry |
127
+ | `spine_eval` | `eval` | dataset + scorers + Cost/Latency/Efficacy/Reliability report |
128
+ | `spine_orchestration` | — | sequential / supervisor / handoff |
129
+ | `spine_cli` | `cli` | `init` / `run` / `chat` / `dev` / `trace` / `eval` / `doctor` / `plugin` |
130
+
131
+ ## Develop
132
+
133
+ ```bash
134
+ uv sync # install workspace + dev deps
135
+ uv run pytest # tests
136
+ uv run ruff check . # lint
137
+ uv run mypy # strict type-check
138
+ uv run mkdocs serve # preview docs at http://127.0.0.1:8000
139
+ ```
140
+
141
+ See the [Contributing guide](https://research-analytics-solutions.github.io/spine/contributing/)
142
+ to build your own [middleware](https://research-analytics-solutions.github.io/spine/develop/middleware/),
143
+ [provider](https://research-analytics-solutions.github.io/spine/develop/provider/), or
144
+ [backend](https://research-analytics-solutions.github.io/spine/develop/publish/) and publish it
145
+ as a plugin.
146
+
147
+ ## License
148
+
149
+ [MIT](LICENSE) © 2026 Research Analytics Solutions
@@ -0,0 +1,89 @@
1
+ <p align="center">
2
+ <img src="docs/assets/logo-hero.svg" alt="Spine" width="110" />
3
+ </p>
4
+
5
+ <h1 align="center">Spine</h1>
6
+
7
+ <p align="center">
8
+ <strong>A lightweight, modular, protocol-native runtime for production AI agents.</strong>
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://github.com/Research-Analytics-Solutions/spine/actions/workflows/ci.yml"><img src="https://github.com/Research-Analytics-Solutions/spine/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
13
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License"></a>
14
+ <img src="https://img.shields.io/badge/python-3.12%2B-blue.svg" alt="Python 3.12+">
15
+ <a href="https://research-analytics-solutions.github.io/spine/"><img src="https://img.shields.io/badge/docs-mkdocs--material-526CFE.svg" alt="Docs"></a>
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://research-analytics-solutions.github.io/spine/">Documentation</a> ·
20
+ <a href="https://research-analytics-solutions.github.io/spine/quickstart/">Quickstart</a> ·
21
+ <a href="https://research-analytics-solutions.github.io/spine/guides/examples/">Cookbook</a> ·
22
+ <a href="https://research-analytics-solutions.github.io/spine/contributing/">Contributing</a>
23
+ </p>
24
+
25
+ ---
26
+
27
+ Spine is the *kernel* for AI agents — a tiny, load-bearing runtime that everything
28
+ else plugs into. Where monolithic frameworks bundle heavy abstractions, Spine
29
+ ships a small core and pushes every feature into **opt-in middleware, swappable
30
+ backends, and protocol adapters**.
31
+
32
+ ```python
33
+ from spine_core import Agent
34
+
35
+ agent = Agent("openai:gpt-4o-mini")
36
+ print((await agent.run("say hello")).answer)
37
+ ```
38
+
39
+ ## Three guarantees
40
+
41
+ - **No hidden prompts** — every model call consumes inspectable, typed `Message` objects.
42
+ - **No runaway loops** — guards are enforced inside the kernel, every iteration.
43
+ - **Deterministic replay** — any run can be recorded and replayed step-for-step.
44
+
45
+ ## Install
46
+
47
+ One package, lean core, opt-in extras:
48
+
49
+ ```bash
50
+ pip install spinekit # kernel only (pydantic + anyio)
51
+ pip install "spinekit[openai]" # + OpenAI
52
+ pip install "spinekit[anthropic,redis,cli]" # pick parts
53
+ pip install "spinekit[all]" # everything
54
+ ```
55
+
56
+ Import name stays `spine_core`. See the [install guide](https://research-analytics-solutions.github.io/spine/install/).
57
+
58
+ ## What's in the box
59
+
60
+ | Module | Extra | What |
61
+ |---|---|---|
62
+ | `spine_core` | — | the kernel — loop, state, guards, tracer, protocols, HITL, streaming |
63
+ | `spine_middleware` | — | retry, fallback, guardrails, cache, memory recall, sandbox, replay, … |
64
+ | `spine_backends` | `redis` / `postgres` | checkpoints (SQLite always; Redis/Postgres) + memory (vector/buffer/pgvector) |
65
+ | `spine_providers` | `openai` / `anthropic` | OpenAI + Anthropic (and any OpenAI-compatible endpoint) |
66
+ | `spine_mcp` · `spine_a2a` · `spine_otel` | `mcp` · `a2a` · `otel` | MCP tools · remote agents · OpenTelemetry |
67
+ | `spine_eval` | `eval` | dataset + scorers + Cost/Latency/Efficacy/Reliability report |
68
+ | `spine_orchestration` | — | sequential / supervisor / handoff |
69
+ | `spine_cli` | `cli` | `init` / `run` / `chat` / `dev` / `trace` / `eval` / `doctor` / `plugin` |
70
+
71
+ ## Develop
72
+
73
+ ```bash
74
+ uv sync # install workspace + dev deps
75
+ uv run pytest # tests
76
+ uv run ruff check . # lint
77
+ uv run mypy # strict type-check
78
+ uv run mkdocs serve # preview docs at http://127.0.0.1:8000
79
+ ```
80
+
81
+ See the [Contributing guide](https://research-analytics-solutions.github.io/spine/contributing/)
82
+ to build your own [middleware](https://research-analytics-solutions.github.io/spine/develop/middleware/),
83
+ [provider](https://research-analytics-solutions.github.io/spine/develop/provider/), or
84
+ [backend](https://research-analytics-solutions.github.io/spine/develop/publish/) and publish it
85
+ as a plugin.
86
+
87
+ ## License
88
+
89
+ [MIT](LICENSE) © 2026 Research Analytics Solutions
@@ -0,0 +1,94 @@
1
+ # Architecture
2
+
3
+ ## Design principles
4
+
5
+ These are binding constraints, not aspirations.
6
+
7
+ 1. **Tiny kernel.** The core is the execution loop, the state model, and the
8
+ guard checks — importable with zero third-party runtime dependencies beyond
9
+ the standard library + Pydantic + anyio.
10
+ 2. **Everything is a plugin.** Each feature is exactly one of: **middleware**
11
+ (wraps a step), **backend** (implements a protocol), or **adapter** (bridges a
12
+ standard). If a feature requires editing the kernel, it was modeled wrong.
13
+ 3. **Pay only for what you import.** A beginner imports nothing extra and writes
14
+ 3 lines. An enterprise stacks a dozen middlewares. Same kernel.
15
+ 4. **Protocol-first.** Consume MCP and A2A rather than inventing proprietary
16
+ equivalents. Lock-in is a non-goal.
17
+ 5. **Observable & deterministic by default.** Every step emits a trace event and
18
+ an OpenTelemetry span. No hidden state, no hidden prompts.
19
+ 6. **Async-first.** The core is `async`; a thin synchronous facade sits on top.
20
+ 7. **Typed and validated.** Pydantic v2 at every boundary.
21
+
22
+ ## The four planes
23
+
24
+ ```mermaid
25
+ flowchart TB
26
+ API["<b>Developer API</b><br/><code>Agent()</code> · <code>@tool</code> · <code>middleware=[...]</code>"]
27
+
28
+ subgraph KERNEL ["🧠 &nbsp;KERNEL &nbsp;·&nbsp; we own"]
29
+ direction LR
30
+ K1[Step loop] ~~~ K2[State] ~~~ K3[Guards] ~~~ K4[Tracer]
31
+ end
32
+
33
+ subgraph MW ["🧩 &nbsp;MIDDLEWARE &nbsp;·&nbsp; opt-in, chainable"]
34
+ direction LR
35
+ M1[Retry] ~~~ M2[Guardrails] ~~~ M3[Cache] ~~~ M4[Compaction] ~~~ M5[Memory]
36
+ end
37
+
38
+ subgraph BE ["🔌 &nbsp;BACKENDS &nbsp;·&nbsp; swappable, behind protocols"]
39
+ direction LR
40
+ B1[Providers] ~~~ B2[Checkpoints] ~~~ B3[Memory stores]
41
+ end
42
+
43
+ subgraph AD ["🌐 &nbsp;ADAPTERS &nbsp;·&nbsp; bridge open standards"]
44
+ direction LR
45
+ A1[MCP] ~~~ A2[A2A] ~~~ A3[OTLP]
46
+ end
47
+
48
+ API --> KERNEL --> MW --> BE --> AD
49
+
50
+ %% stroke-only accents — no fill/text-color overrides, so text follows the
51
+ %% Material theme and stays readable in both light and dark mode.
52
+ classDef api stroke:#6366f1,stroke-width:2px;
53
+ classDef kernel stroke:#4f46e5,stroke-width:2.5px;
54
+ classDef plane stroke:#94a3b8,stroke-width:1.5px;
55
+ class API api;
56
+ class KERNEL kernel;
57
+ class MW,BE,AD plane;
58
+ ```
59
+
60
+ The kernel never *constructs* behavior; it *invokes hooks*. Middlewares attach to
61
+ defined hook points; backends sit behind tiny protocols; adapters translate open
62
+ standards.
63
+
64
+ ## Repository layout
65
+
66
+ ```
67
+ spine/
68
+ ├── packages/
69
+ │ ├── spine-core/ # kernel, protocols, guards, tracer
70
+ │ ├── spine-cli/ # Typer CLI + templates + dev server
71
+ │ ├── spine-providers/ # OpenAI, Anthropic adapters
72
+ │ ├── spine-middleware/ # the middleware suite
73
+ │ ├── spine-backends/ # sqlite/redis/postgres + vector/buffer/pgvector
74
+ │ ├── spine-mcp/ # MCP client adapter
75
+ │ ├── spine-a2a/ # A2A adapter
76
+ │ ├── spine-otel/ # OpenTelemetry middleware
77
+ │ ├── spine-eval/ # eval harness + scorers
78
+ │ └── spine-orchestration/# sequential / supervisor / handoff
79
+ └── docs/
80
+ ```
81
+
82
+ The source is organized by plane under `packages/*/src/` (import names
83
+ `spine_core`, `spine_providers`, …), but it all ships as **one distribution,
84
+ `spinekit`** — a lean core (Pydantic + anyio) with heavy dependencies as opt-in
85
+ extras (`spinekit[openai]`, `spinekit[redis]`, `spinekit[all]`, …). The code is
86
+ small; only the third-party dependencies are optional.
87
+
88
+ ## The bet
89
+
90
+ The integration layer that made monolithic frameworks valuable has been
91
+ commoditized by open standards. The durable value sits in the **reliability
92
+ runtime** — the execution loop, guards, durable state, and observability that
93
+ decide whether an agent survives production. Spine owns that core and lets the
94
+ standards do the integration.
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none" role="img" aria-label="Spine">
2
+ <rect width="32" height="32" rx="7" fill="#5b5bd6"/>
3
+ <rect x="14.4" y="4" width="3.2" height="24" rx="1.6" fill="#ffffff" opacity="0.55"/>
4
+ <rect x="8.5" y="5.5" width="15" height="3.1" rx="1.55" fill="#ffffff"/>
5
+ <rect x="7.2" y="10.8" width="17.6" height="3.1" rx="1.55" fill="#ffffff"/>
6
+ <rect x="7.2" y="16.1" width="17.6" height="3.1" rx="1.55" fill="#ffffff"/>
7
+ <rect x="8.5" y="21.4" width="15" height="3.1" rx="1.55" fill="#ffffff"/>
8
+ </svg>
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 96" fill="none" role="img" aria-label="Spine">
2
+ <defs>
3
+ <linearGradient id="g" x1="0" y1="0" x2="96" y2="96" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#818cf8"/>
5
+ <stop offset="1" stop-color="#4f46e5"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <rect x="42" y="10" width="12" height="76" rx="6" fill="url(#g)" opacity="0.45"/>
9
+ <rect x="24" y="14" width="48" height="10.5" rx="5.25" fill="url(#g)"/>
10
+ <rect x="19" y="31" width="58" height="10.5" rx="5.25" fill="url(#g)"/>
11
+ <rect x="19" y="48" width="58" height="10.5" rx="5.25" fill="url(#g)"/>
12
+ <rect x="24" y="65" width="48" height="10.5" rx="5.25" fill="url(#g)"/>
13
+ <rect x="32" y="82" width="32" height="8" rx="4" fill="url(#g)" opacity="0.8"/>
14
+ </svg>