Skip to content

feat(sparc-service): one-command install; deploy SPARC via a shared i…#479

Merged
huang195 merged 1 commit into
rossoctl:mainfrom
OsherElhadad:feat/sparc-service-install
Jun 4, 2026
Merged

feat(sparc-service): one-command install; deploy SPARC via a shared i…#479
huang195 merged 1 commit into
rossoctl:mainfrom
OsherElhadad:feat/sparc-service-install

Conversation

@OsherElhadad

@OsherElhadad OsherElhadad commented Jun 4, 2026

Copy link
Copy Markdown

…nstaller

The SPARC service deploy artifacts don't belong in the kagenti Helm chart, so move them here next to the rest of SPARC. Add authbridge/sparc-service/deploy: a single make install that configures the provider (watsonx by default, or ollama/openai/azure/litellm) and deploys the service into a cluster — run once, before enabling the sparc plugin on any agent. Publish the sparc-service image from CI so the default install needs no local build (a local make image path remains for kind).

Point the finance-sparc demo at the same installer instead of carrying its own copy of the manifest, so there is one source of truth, and make the demo's verdict summary scan every session so it reports reliably regardless of which session the agent's outbound calls land in.

Summary

Related issue(s)

(Optional) Testing Instructions

Fixes #

Summary by CodeRabbit

Release Notes

  • New Features

    • Added deployment automation and documentation for the SPARC reflection service, including a one-command installation flow with provider-specific configuration options (watsonx, Ollama, LiteLLM).
  • Documentation

    • Enhanced SPARC plugin documentation with prerequisite deployment guidance.
    • Updated demo README to clarify SPARC service is deployed separately from the demo application.
  • Refactor

    • Reorganized SPARC service deployment to use a shared installer; demo now delegates service setup to centralized deployment tooling.
    • Updated verdict reporting to query live API endpoints instead of static snapshots.

…nstaller

The SPARC service deploy artifacts don't belong in the kagenti Helm chart, so
move them here next to the rest of SPARC. Add authbridge/sparc-service/deploy:
a single `make install` that configures the provider (watsonx by default, or
ollama/openai/azure/litellm) and deploys the service into a cluster — run once,
before enabling the `sparc` plugin on any agent. Publish the sparc-service image
from CI so the default install needs no local build (a local `make image` path
remains for kind).

Point the finance-sparc demo at the same installer instead of carrying its own
copy of the manifest, so there is one source of truth, and make the demo's
verdict summary scan every session so it reports reliably regardless of which
session the agent's outbound calls land in.

Signed-off-by: Osher-Elhadad <Osher.Elhadad@ibm.com>
@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR decouples SPARC reflection service deployment from the finance-sparc demo by introducing a shared, reusable Kubernetes deployment infrastructure. The service deployment is relocated to authbridge/sparc-service/deploy/ with configurable Makefile targets; the demo and CI workflows are updated to use this shared infrastructure. Verdict collection scripts are refactored to aggregate results from a live sessions API instead of single-session snapshots.

Changes

SPARC Service Shared Deployment

Layer / File(s) Summary
Shared deployment orchestration and manifest
authbridge/sparc-service/deploy/Makefile, authbridge/sparc-service/deploy/README.md, authbridge/sparc-service/deploy/sparc-service.yaml
New deploy/Makefile provides install, uninstall, image, status, and help targets to orchestrate SPARC service lifecycle with configurable provider, namespace, image, model, credentials, and kind cluster parameters. Workload manifest is updated from demo-specific to AuthBridge-oriented labels and published image references. Complete deployment guide documentation is added.
Finance-sparc demo integration with shared installer
authbridge/demos/finance-sparc/Makefile, authbridge/demos/finance-sparc/README.md
Demo's deploy target now delegates to make -C $(SPARC_DEPLOY) install instead of local kubectl apply, passing namespace, image, provider, model, and configuration. undeploy similarly delegates to make uninstall. Demo documentation clarifies SPARC service as a separate prerequisite deployed before the demo workload.
Verdict collection via live HTTP sessions API
authbridge/demos/finance-sparc/scripts/show-verdicts.py, authbridge/demos/finance-sparc/scripts/drive-demo.sh
show-verdicts.py is rewritten to fetch and aggregate SPARC verdicts from live /v1/sessions and /v1/sessions/{id} endpoints instead of reading stdin, de-duplicating results across all sessions. drive-demo.sh is updated to invoke the verdict script with the agent HTTP base URL.
Documentation and CI integration
authbridge/docs/sparc-plugin.md, authbridge/sparc-service/README.md, .github/workflows/build.yaml
sparc-plugin.md documents the required SPARC service prerequisite and deployment command. sparc-service/README.md adds a quick-start "one-command deployment" section with provider-specific examples. Docker build matrix includes sparc-service image.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A service once tethered to a demo now runs free,
Shared by all who call upon its LLM majesty!
Verdicts flow from live sessions, no snapshot old,
With Makefile magic, deployment stories unfold. 🎭✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: introducing a one-command install mechanism for deploying SPARC via a shared installer, which is the central objective of this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/kagenti/kagenti-extensions/issues/comments/4621720222","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/kagenti/kagenti-extensions/pull/479?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: defaults\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro Plus\n> \n> **Run ID**: `d9ba4f6c-fb73-484e-b79a-5248ba32a837`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between a7ebd87b129dbaa2ecc5577da4a65ae5eb299f6d and 179526d9c0b3cd10eaef48ab6f511ed9027a56a6.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (10)</summary>\n> \n> * `.github/workflows/build.yaml`\n> * `authbridge/demos/finance-sparc/Makefile`\n> * `authbridge/demos/finance-sparc/README.md`\n> * `authbridge/demos/finance-sparc/scripts/drive-demo.sh`\n> * `authbridge/demos/finance-sparc/scripts/show-verdicts.py`\n> * `authbridge/docs/sparc-plugin.md`\n> * `authbridge/sparc-service/README.md`\n> * `authbridge/sparc-service/deploy/Makefile`\n> * `authbridge/sparc-service/deploy/README.md`\n> * `authbridge/sparc-service/deploy/sparc-service.yaml`\n> \n> </details>\n> \n> ```ascii\n>  ______________________________________________________\n> < Multiplying to perform multi-threaded bug detection. >\n>  ------------------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\n\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}}}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@authbridge/demos/finance-sparc/scripts/show-verdicts.py`:
- Around line 13-18: Add Python 3.12 type annotations for the module-level state
and function signature: annotate BASE as str | None (or str if always a string),
add a return type and parameter types to get (e.g., def get(path: str) -> Any or
dict[str, Any] as appropriate), and annotate the top-level containers seen and
rows (e.g., set[str], list[dict[str, Any]]). Use modern union syntax (A | B)
where needed and import typing-only symbols (Any, dict) if required.

In `@authbridge/sparc-service/deploy/Makefile`:
- Around line 70-73: The Makefile currently builds a sec string from CRED_VARS
and always runs the kubectl create secret command even when sec is empty, which
causes failure for credential-less installs; change the install logic to check
if the computed sec variable is non-empty before invoking "kubectl -n
$(NAMESPACE) create secret generic sparc-creds $$sec --dry-run=client -o yaml |
kubectl apply -f -", e.g. after the loop test "[ -n \"$$sec\" ] && (kubectl ...
) || echo 'no credentials; skipping secret creation'", ensuring you reference
the same sec and CRED_VARS variables used in the snippet so the secret command
is only executed when at least one --from-literal was appended.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d9ba4f6c-fb73-484e-b79a-5248ba32a837

📥 Commits

Reviewing files that changed from the base of the PR and between a7ebd87 and 179526d.

📒 Files selected for processing (10)
  • .github/workflows/build.yaml
  • authbridge/demos/finance-sparc/Makefile
  • authbridge/demos/finance-sparc/README.md
  • authbridge/demos/finance-sparc/scripts/drive-demo.sh
  • authbridge/demos/finance-sparc/scripts/show-verdicts.py
  • authbridge/docs/sparc-plugin.md
  • authbridge/sparc-service/README.md
  • authbridge/sparc-service/deploy/Makefile
  • authbridge/sparc-service/deploy/README.md
  • authbridge/sparc-service/deploy/sparc-service.yaml

Comment on lines +13 to +18
BASE = sys.argv[1] if len(sys.argv) > 1 else "http://localhost:19094"


def get(path):
with urllib.request.urlopen(BASE + path, timeout=10) as resp:
return json.load(resp)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add Python 3.12 type hints for script interfaces and state

authbridge/demos/finance-sparc/scripts/show-verdicts.py (under authbridge/**/*.py) has untyped top-level state and function/interface code (BASE, get, and likely seen/rows at 27-28), violating the repo’s Python 3.12 typing rule. Add explicit type hints using modern union syntax (e.g., str | None).

🧰 Tools
🪛 Ruff (0.15.15)

[error] 17-17: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/demos/finance-sparc/scripts/show-verdicts.py` around lines 13 -
18, Add Python 3.12 type annotations for the module-level state and function
signature: annotate BASE as str | None (or str if always a string), add a return
type and parameter types to get (e.g., def get(path: str) -> Any or dict[str,
Any] as appropriate), and annotate the top-level containers seen and rows (e.g.,
set[str], list[dict[str, Any]]). Use modern union syntax (A | B) where needed
and import typing-only symbols (Any, dict) if required.

Comment on lines +70 to +73
@sec=""; for v in $(CRED_VARS); do \
val=$$(printenv $$v || true); [ -n "$$val" ] && sec="$$sec --from-literal=$$v=$$val"; \
done; \
kubectl -n $(NAMESPACE) create secret generic sparc-creds $$sec --dry-run=client -o yaml | kubectl apply -f -

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid creating an empty Secret in install.

When none of $(CRED_VARS) is set (for example PROVIDER=ollama), kubectl create secret generic sparc-creds $$sec ... runs with no --from-* flags and fails, which breaks the intended credential-less install path.

🔧 Suggested fix
 	`@sec`=""; for v in $(CRED_VARS); do \
 	  val=$$(printenv $$v || true); [ -n "$$val" ] && sec="$$sec --from-literal=$$v=$$val"; \
 	done; \
-	kubectl -n $(NAMESPACE) create secret generic sparc-creds $$sec --dry-run=client -o yaml | kubectl apply -f -
+	if [ -n "$$sec" ]; then \
+	  kubectl -n $(NAMESPACE) create secret generic sparc-creds $$sec --dry-run=client -o yaml | kubectl apply -f -; \
+	else \
+	  kubectl -n $(NAMESPACE) delete secret sparc-creds --ignore-not-found >/dev/null; \
+	fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@sec=""; for v in $(CRED_VARS); do \
val=$$(printenv $$v || true); [ -n "$$val" ] && sec="$$sec --from-literal=$$v=$$val"; \
done; \
kubectl -n $(NAMESPACE) create secret generic sparc-creds $$sec --dry-run=client -o yaml | kubectl apply -f -
`@sec`=""; for v in $(CRED_VARS); do \
val=$$(printenv $$v || true); [ -n "$$val" ] && sec="$$sec --from-literal=$$v=$$val"; \
done; \
if [ -n "$$sec" ]; then \
kubectl -n $(NAMESPACE) create secret generic sparc-creds $$sec --dry-run=client -o yaml | kubectl apply -f -; \
else \
kubectl -n $(NAMESPACE) delete secret sparc-creds --ignore-not-found >/dev/null; \
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@authbridge/sparc-service/deploy/Makefile` around lines 70 - 73, The Makefile
currently builds a sec string from CRED_VARS and always runs the kubectl create
secret command even when sec is empty, which causes failure for credential-less
installs; change the install logic to check if the computed sec variable is
non-empty before invoking "kubectl -n $(NAMESPACE) create secret generic
sparc-creds $$sec --dry-run=client -o yaml | kubectl apply -f -", e.g. after the
loop test "[ -n \"$$sec\" ] && (kubectl ... ) || echo 'no credentials; skipping
secret creation'", ensuring you reference the same sec and CRED_VARS variables
used in the snippet so the secret command is only executed when at least one
--from-literal was appended.

@huang195 huang195 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — clean structural refactor ✅

The headline of this PR is a directory-structure correction, and it's done right: the SPARC reflection-service manifest moves out of the demo's k8s/ folder into authbridge/sparc-service/deploy/, co-located with the service it deploys, and the demo now consumes that shared installer instead of carrying its own copy (single source of truth). Verified the old manifest is gone from the demo k8s/, the README's k8s/{agent,finance-mcp}.yaml reference matches reality, and the new CI build entry points at a real Dockerfile. Manifest hygiene is good (resource requests/limits, non-root, readiness/liveness probes, namespace de-baked). All 20 CI checks pass; single commit, signed-off.

A note on authbridge/sparc-service/ placement (non-blocking)

Worth separating two things that share the "sparc" name:

  • The sparc plugin lives at authbridge/authlib/plugins/sparc/, next to its 6 peers — correctly placed.
  • sparc-service is not the plugin; it's a standalone Python LLM-reflection backend the plugin calls over HTTP (own image, own lifecycle), so it can't live under authlib/plugins/.

That directory is pre-existing on main — this PR only adds deploy/ inside it — so it's not in scope to gate here. The legitimate structural observation is one level up: SPARC is the only plugin that ships a backend service, and that service sits as a top-level authbridge/ sibling (alongside authlib, cmd, demos, docs, proxy-init). That's fine while it's the only one, but it won't scale — if another plugin later grows an out-of-process backend, a convention like authbridge/services/<name>/ would be cleaner than a top-level dir per service. Suggest tracking that as a follow-up issue rather than addressing it here.

Areas reviewed

Directory structure, Helm/K8s manifest, Makefiles, Python (show-verdicts.py), Docs, CI build matrix.

Verdict: APPROVE — no must-fix issues; comments below are 1 suggestion + 2 nits.

# ConfigMap and the optional `sparc-watsonx` Secret, both created by the
# Makefile (provider-aware: watsonx or ollama). In production this ships via the
# kagenti Helm chart (components.sparcService.enabled=true).
# SPARC reflection service — the backend the AuthBridge `sparc` plugin calls.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (cross-repo, non-blocking): the previous version of this manifest noted the service "ships via the kagenti Helm chart (components.sparcService.enabled=true)". This PR moves to an installer-based model. If that Helm path still exists in kagenti/kagenti, it now diverges from this installer — the same two-sources-of-truth problem this PR fixes within-repo, just across repos. Worth confirming the chart side is reconciled or opening a tracking issue.

@echo "[*] SPARC service ready at http://sparc-service.$(NAMESPACE).svc:$(PORT)/reflect"
@echo " Now enable the 'sparc' plugin in an agent's authbridge config (see docs/sparc-plugin.md)."

status: ## Show the SPARC service deployment + config

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: kubectl get deploy,svc,cm/sparc-service-config -l app.kubernetes.io/name=sparc-service — the -l selector also filters the explicitly-named ConfigMap, which install creates without that label, so it won't show on this line. Harmless (the following kubectl ... cm sparc-service-config -o yaml covers it), but the label filter on a named resource is inconsistent.

@printf "\nVars: PROVIDER(=%s) NAMESPACE(=%s) IMAGE MODEL TRACK OLLAMA_BASE_URL\n" "$(PROVIDER)" "$(NAMESPACE)"
@printf " LLM_KWARGS_JSON LLM_REGISTRY_ID KIND_CLUSTER_NAME\n\n"

image: ## Build the sparc-service image locally and load it into kind

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ctr ... tag localhost/$(IMAGE) docker.io/library/$(IMAGE) produces a doubled-registry ref (docker.io/library/ghcr.io/...) since IMAGE is a full ghcr path by default. It's || true defensive and mirrors the demo's existing pattern, so it won't break — just noting it likely no-ops for the ghcr-tagged default image.

@huang195
huang195 merged commit aa2b115 into rossoctl:main Jun 4, 2026
20 checks passed
@github-project-automation github-project-automation Bot moved this from New /:ToDo to Done in Rossoctl Issue Prioritization Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants