Starting a New Agentic Project
This guide lays out a new agent project on top of Ark and tests it end to end. It assumes the Quickstart is done — Ark is running and ark, kubectl work against your cluster.
Project Layout
Ark provides the runtime; your project — agents, tools, teams, queries — lives in its own directory (and usually its own repository). That separation lets each team evolve its agents independently of the platform.
There’s no required layout. The convention below is a starting point.
Prerequisites
- Ark installed
kubectlconfigured- A model named
default(ark models create default)
ark --version
kubectl get pods -n ark-system
kubectl get modelsStep 1: Directory
mkdir -p my-agents/{agents,teams,queries,tools,mcp-servers}
cd my-agentsFrom here, every resource is a YAML file you write and apply with kubectl.
Step 2: First Agent
cat > agents/customer-support.yaml <<'EOF'
apiVersion: ark.mckinsey.com/v1alpha1
kind: Agent
metadata:
name: customer-support
spec:
description: Handles customer inquiries and support tickets
modelRef:
name: default
prompt: |
You are a helpful customer support assistant.
Help users with their questions and issues professionally.
EOF
kubectl apply -f agents/customer-support.yaml
kubectl get agent customer-support -o jsonpath='{.status.phase}'
# readyStep 3: Tool
An HTTP tool that calls the National Weather Service:
cat > tools/get-forecast.yaml <<'EOF'
apiVersion: ark.mckinsey.com/v1alpha1
kind: Tool
metadata:
name: get-forecast
spec:
type: http
description: Get weather forecast for a location and time period
inputSchema:
type: object
required: ["office", "gridX", "gridY"]
properties:
office:
type: string
description: "Weather office identifier (e.g., TOP)"
gridX:
type: integer
description: "Grid X coordinate"
gridY:
type: integer
description: "Grid Y coordinate"
http:
url: https://api.weather.gov/gridpoints/{office}/{gridX},{gridY}/forecast
EOF
kubectl apply -f tools/get-forecast.yamlSee Tools for MCP, builtin, and agent-as-tool variants.
Step 4: Team
Pick a strategy — each one expects a slightly different shape. See Teams → Strategy walkthroughs for the full reference.
Sequential
Members run in declared order, one pass each:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: support-team-sequential
spec:
description: Triage, then specialist
strategy: sequential
members:
- type: agent
name: customer-support
- type: agent
name: order-tracker
- type: agent
name: escalation-handlerSequential with Loops
Cycle through members until maxTurns is reached. loops: true and maxTurns must be set together:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: support-team-loops
spec:
description: Each member contributes in turn until maxTurns
strategy: sequential
loops: true
maxTurns: 5
members:
- type: agent
name: customer-support
- type: agent
name: order-trackerstrategy: round-robin is deprecated and silently migrated to sequential with loops: true. Use the form above directly.
Selector
A nominated agent picks the next member. selector.agent and maxTurns are required. Loops are not allowed on selector teams. The selectorPrompt should instruct the agent to use the built-in select-next-speaker tool:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: support-team-selector
spec:
description: Selector agent picks the right specialist
strategy: selector
maxTurns: 10
members:
- type: agent
name: customer-support
- type: agent
name: order-tracker
selector:
agent: planner-agent
selectorPrompt: |
Choose the team member best suited to respond next.
Available roles:
{{.Roles}}
Conversation history:
{{.History}}
Use the select-next-speaker tool to make your selection.strategy: graph is deprecated and migrated to plain sequential with edges discarded. For graph-style routing inside a selector team, see Teams → Selector with graph.
Apply the chosen team:
kubectl apply -f teams/support-team-sequential.yaml
kubectl get team support-team-sequentialStep 5: MCP Server (Optional)
Expose external capabilities via the Model Context Protocol:
cat > mcp-servers/example.yaml <<'EOF'
apiVersion: ark.mckinsey.com/v1alpha1
kind: MCPServer
metadata:
name: example-mcp
spec:
address:
value: "http://example-mcp.default.svc.cluster.local:8080/mcp"
transport: http
timeout: 1m
EOF
kubectl apply -f mcp-servers/example.yamlFor authentication and OAuth, see MCP Servers.
Step 6: Query
cat > queries/test-support.yaml <<'EOF'
apiVersion: ark.mckinsey.com/v1alpha1
kind: Query
metadata:
name: test-support
spec:
input: "I need help with my order #12345"
target:
type: agent
name: customer-support
EOF
kubectl apply -f queries/test-support.yamlWatch it complete and inspect the response:
kubectl get query test-support -w
# Phase: pending -> running -> done
kubectl get query test-support -o jsonpath='{.status.response.content}'Step 7: End-to-End Testing
Bash smoke script
cat > test-workflow.sh <<'EOF'
#!/bin/bash
set -e
kubectl apply -f agents/
kubectl apply -f tools/
kubectl apply -f teams/
kubectl wait --for=jsonpath='{.status.phase}'=ready agent/customer-support --timeout=60s
kubectl apply -f queries/test-support.yaml
kubectl wait --for=jsonpath='{.status.phase}'=done query/test-support --timeout=120s
RESPONSE=$(kubectl get query test-support -o jsonpath='{.status.response.content}')
[ -n "$RESPONSE" ] || { echo "FAIL: empty response"; exit 1; }
echo "PASS"
echo "Response: $RESPONSE"
kubectl delete query test-support
EOF
chmod +x test-workflow.sh
./test-workflow.shChainsaw (recommended)
Declarative, repeatable tests via Chainsaw :
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
name: customer-support-workflow
spec:
steps:
- name: apply-resources
try:
- apply:
file: agents/customer-support.yaml
- apply:
file: queries/test-support.yaml
- name: wait-for-agent-ready
try:
- assert:
resource:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Agent
metadata:
name: customer-support
status:
phase: ready
- name: verify-query-done
try:
- assert:
resource:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Query
metadata:
name: test-support
status:
phase: done
(length(responses) > `0`): true
(length(responses[0].content) > `10`): true
- name: cleanup
try:
- delete:
ref:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Query
name: test-supportRun it:
chainsaw test --test-file chainsaw-test.yamlStep 8: Iterate
Add agents as YAML files and apply the directory:
# agents/order-tracker.yaml, agents/product-recommender.yaml, ...
kubectl apply -f agents/Wire them into a richer team:
apiVersion: ark.mckinsey.com/v1alpha1
kind: Team
metadata:
name: full-support-team
spec:
description: Complete customer support workflow
strategy: sequential
members:
- type: agent
name: customer-support
- type: agent
name: order-tracker
- type: agent
name: escalation-handlerBest Practices
Organise by feature
my-agents/
├── features/
│ ├── customer-support/
│ │ ├── agents/
│ │ ├── tools/
│ │ ├── queries/
│ │ └── tests/
│ └── order-processing/
│ ├── agents/
│ ├── tools/
│ └── tests/Version control
git init
git add .
git commit -m "feat: initial Ark project setup"Per-environment overlays with Kustomize
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- agents/
- tools/
- teams/
namespace: my-agents-prodContinuous testing in CI
name: Test Ark Agents
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup K3s
run: curl -sfL https://get.k3s.io | sh -
- name: Install Ark
run: ark install -y
- name: Run Tests
run: chainsaw test --test-dir tests/Troubleshooting
Agent stuck before ready
kubectl describe agent customer-support
kubectl logs -n ark-system -l app=ark-controller
kubectl get modelsQuery stuck
kubectl get query test-support -o yaml
kubectl get query test-support -o jsonpath='{.status.error}'
kubectl get events --field-selector involvedObject.name=test-supportTool returns nothing
kubectl get tool get-forecast
kubectl describe tool get-forecastNext Steps
- Complete Worked Example — end-to-end customer-support walkthrough
- Ark Dashboard
- Models
- Agents
- Teams
- End-to-End Testing