feat(agents): scaffold Condukt-backed agentic workflow infrastructure#30
Merged
Conversation
Add an AGENTS.md convention that documentation should describe behavior from the operator/end-user perspective and not leak internal module names, function signatures, or refactoring artifacts. Internals stay in code and AGENTS.md; user-facing surfaces (README.md) describe outcomes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror the setup that powers Atlas's AI features so adding an agent in Hive is a single-file change: - Pull in :condukt 1.7.0 from tuist/condukt. - Read HIVE_LLM_API_KEY / HIVE_LLM_MODEL / HIVE_LLM_BASE_URL into `:hive, :llm` in config/runtime.exs. When the key is unset the LLM stays unconfigured and the rest of Hive boots normally, so self-hosters who don't want agentic features can deploy without an LLM. - Add `Hive.Agents` (config/0, enabled?/0, client_opts/0), `Hive.Agents.Sessions` (single call site wrapping `Condukt.run/3` and `Condukt.Operation.run/4` and merging in the LLM options), and `Hive.Agents.StyleGuide` (cross-cutting prose rules that every agent appends to its `system_prompt/0`). - Provide `Hive.TestSupport.Agents.NoopAgent` + NoopRuntime so tests that don't need a real LLM round-trip can still exercise a `use Condukt` module, and Mimic-copy Condukt in test_helper.exs so stubs work across async tests without `Application.put_env`. - Document the env vars and the "Adding an agent" walkthrough in AGENTS.md, and surface Condukt in Tech Stack and Layout so the docs describe the new directory layout. DB-backed session/event audit, the audit LiveView, and any sandbox Helm overlay are deferred until the first concrete agent lands, so this PR ships the minimum surface to unblock that work without dead code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror Atlas's production LLM setup so the agentic scaffolding in this PR is actually reachable on hive.tuist.dev: - Add HIVE_LLM_MODEL (openai:accounts/fireworks/models/kimi-k2p5) and HIVE_LLM_BASE_URL (https://api.fireworks.ai/inference/v1) to the env block. Same provider, model, and endpoint as Atlas so we share rate limits and capacity planning, and so anyone reading both charts sees one consistent picture. - Bind HIVE_LLM_API_KEY to the 1Password item hive-llm-api-key/credential via External Secrets. The 1Password item itself is created out-of-band; this PR only wires up the chart side. Self-hosters who don't load values-production.yaml are unaffected: the chart's generic defaults leave HIVE_LLM_API_KEY unset, and Hive.Agents returns {:error, :llm_not_configured} until they set it themselves. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a Self-hosting > Agents page sibling to Authentication that covers HIVE_LLM_API_KEY / HIVE_LLM_MODEL / HIVE_LLM_BASE_URL, what happens when the API key is unset, and provider-shaped examples for Anthropic, OpenAI, and OpenAI-compatible gateways such as Fireworks. This is the destination self-hosters will look for once they hear Hive has agentic features, and keeps Deployment focused on Helm plumbing rather than feature toggles. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Note in the Agents page that ReqLLM's catalog is sourced from models.dev so operators know where to look up valid `provider:model_id` values for HIVE_LLM_MODEL. - Drop the Authentication bullet from "Why Hive". It describes a configuration detail (OIDC delegation), not a product capability that belongs in a "what Hive is" overview alongside Specs and Forage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Blick review didn't runThe See the workflow run for details: https://github.com/tuist/hive/actions/runs/27428396515 Commit: |
fortmarek
approved these changes
Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
I want Hive to be the place where Tuist's agentic meadow workflows live, and right now there's no agent infrastructure here at all. Atlas already runs a production Condukt setup that we like, so this PR stands up the equivalent scaffolding in Hive so adding an agent becomes a single-file change rather than a multi-day plumbing exercise.
While I was at it, I added a small AGENTS.md convention that documentation should describe behavior from the operator's perspective and not leak internal module names or refactoring artifacts. That bullet is the original reason this branch existed; the Condukt scaffolding grew from a follow-up question in the same session.
What's in the PR
Condukt scaffolding (
feat(agents)):condukt1.7.0 fromtuist/condukt, pinned the same way Atlas pins it.HIVE_LLM_API_KEY/HIVE_LLM_MODEL/HIVE_LLM_BASE_URLread into:hive, :llminconfig/runtime.exs. When the API key is unset, the LLM stays unconfigured and the rest of Hive boots normally, so self-hosters who do not want agentic features can deploy without an LLM.Hive.Agentsexposesconfig/0,enabled?/0, andclient_opts/0.Hive.Agents.Sessionsis the single call site wrappingCondukt.run/3andCondukt.Operation.run/4and merging in the LLM options, so individual agents stay free of LLM plumbing and so a future audit-trail layer has one place to hook in.Hive.Agents.StyleGuide.prose_rules/0carries the cross-cutting style rules every agent appends to itssystem_prompt/0.Hive.TestSupport.Agents.NoopAgent+NoopRuntimemirror Atlas's pattern: a minimaluse Conduktmodule backed by a runtime that returns{:ok, "handled: " <> prompt}, useful for code that needs a real agent module without an LLM round-trip.Mimic.copy(Condukt, type_check: true)is added intest/test_helper.exsso async tests can stub at the framework boundary.lib/hive/agents/plus thelib/hive/<domain>/agents/<name>_agent.exconvention, and a new## Agentssection with the env vars and a five-step "Adding an agent" walkthrough.Documentation guidance (
docs(agents))A new bullet in the Conventions section saying docs should describe behavior and outcomes from the user's perspective, not internal module names, function signatures, code paths, or refactoring artifacts.
Approach and trade-offs considered
I weighed a couple of options before settling on this shape:
TelemetryHandlerthat streams Condukt's telemetry into those rows, a Sessions LiveView for the audit UI, and a Helm overlay (agent-sandboxes.yaml) that provisions a separate Kubernetes namespace for sandboxed pods. Porting all of that now would mean writing migrations, schemas, UI, and infra for a system with zero agents to feed it. I chose to defer those layers to the PR that lands the first concrete agent, where we will know what we actually need to record.Hive.Agents.Sessionsis structured so audit hooks slot in without changing any agent's call site.HIVE_prefix vs. rawLLM_*. Atlas usesLLM_API_KEY/LLM_MODEL/LLM_BASE_URL. Hive's existing env-var convention is to namespace everything (HIVE_GOOGLE_CLIENT_ID,HIVE_OIDC_ISSUER,HIVE_S3_BUCKET, etc.) so I went withHIVE_LLM_*for consistency with the rest of runtime.exs.ReqLLM.Modelstruct vs. passing the model string through. Atlas's Runner constructs aReqLLM.Modeland pattern-matches on the provider so unsupported providers raise at config time. Condukt accepts a raw"provider:model_id"string and forwards it to ReqLLM, so I pass the string directly and let ReqLLM handle the parsing. We can revisit if we ever need provider-level guardrails.Hive.Agentsmodule vs.Hive.LLMs+Hive.LLMs.Runnersplit. Atlas splits LLM config and runtime helpers across two modules because it has dozens of agents and multiple invocation sites. Hive has none, so I folded both intoHive.Agentsand kept the surface small. If it gets unwieldy we can split later.Verification
mix deps.getresolved the new tree (Condukt plus the transitives it pulls).mix compile --warnings-as-errorsclean in:devand:test. The remaining warnings come from timex and puid (transitive deps) and are pre-existing.mix formatrun on every touched file.lib/atlas/llms.ex,lib/atlas/llms/runner.ex,lib/atlas/agents/sessions.ex,lib/atlas/agents/style_guide.ex,test/support/agents/,test/test_helper.exs) to make sure the public shapes line up.Follow-ups