Create and update Harness AI agent instances - standalone templates for agentic workflows in pipelines. Use when asked to create agent, update agent, modify agent spec, build autonomous systems, or work with AI agents.
88
85%
Does it follow best practices?
Impact
89%
6.84xAverage score across 3 eval scenarios
Low
Low-risk findings worth noting
Create and update Harness AI agent instances - standalone templates used as building blocks in pipelines for automated code, agentic workflows, and infrastructure tasks.
Follow this workflow to create or update an agent. This is INTERACTIVE — show YAML for review and wait for confirmation before creating/updating the agent.
IMPORTANT: Before creating a new agent, check if an existing one can solve the use case.
harness_list with resource_type="agent" (include org_id and project_id if scoped to a project)
harness_get with resource_type="agent" and agent_id to retrieve the current agent configuration
spec, name, description, and other fieldsharness_update (not harness_create) to update the agent with only the fields that need modificationIf creating a new agent or updating an existing one, collect the following before generating YAML:
ca_, then lowercase the name, convert spaces and hyphens (-) to _, replace any remaining non-alphanumeric runs with _, collapse duplicate _, and trim leading/trailing _ from the slug portion (e.g. "Code Coverage Agent" → ca_code_coverage_agent, "PR Reviewer" → ca_pr_reviewer)Ask and clarify the following with the user:
Based on requirements, recommend and verify with the user:
Task instructions (task field):
${{inputs.fieldName}} syntax inside PLUGIN_TASK and other env vars## RULES section at the end with constraints formatted as markdown bullet pointsRuntime inputs (inputs section in spec):
default value for every non-required input — if ${{inputs.fieldName}} is referenced in PLUGIN_TASK or any env var and no value is supplied at runtime nor a default exists, the agent will error at execution timeallowedDomains so users understand and control non-LLM/non-MCP network accessConnectors:
Present this recommended configuration to the user and iterate until confirmed.
Agent Structure: Agents use agent.step.group.steps format — the run step is nested inside a named step group.
Default structure:
version: 1
agent:
step:
group:
steps:
- name: Agent
if: <+Always>
id: agent
run:
container:
image: pkg.harness.io/vrvdt5ius7uwygso8s0bia/harness-agents/harness-ai-agent:latest
env:
PLUGIN_TASK: |
<step-by-step task instructions>
PLUGIN_MAX_TURNS: 150
PLUGIN_HARNESS_CONNECTOR: ${{inputs.llmConnector.id}}
PLUGIN_ALLOWED_DOMAINS: ${{inputs.allowedDomains}}Required environment variables:
env:
PLUGIN_TASK: | # Task instructions go here as a multiline string
<step-by-step instructions>
PLUGIN_MAX_TURNS: 150 # Adjust 100-200 based on task complexity
PLUGIN_HARNESS_CONNECTOR: ${{inputs.llmConnector.id}} # References llmConnector input's id property
PLUGIN_ALLOWED_DOMAINS: ${{inputs.allowedDomains}} # Regexes for additional network accessMCP configuration (only if external services needed):
env:
PLUGIN_MCP_FORMAT: harness
PLUGIN_MCP_SERVERS: <+connectorInputs.resolveList(<+inputs.mcpConnectors>)> # References mcpConnectors inputOptional model override (only if user explicitly requests it):
env:
ANTHROPIC_MODEL: ${{inputs.modelName}} # Only add when user insists on a modelName inputRequired inputs (always include):
agent:
inputs:
llmConnector:
type: connector
required: true
default: your_llm_connector_id # User must replace with actual connector ID
ui:
connectorCategories:
- AI
allowedDomains:
type: string
default: ""Network access: Agent network access is limited to the LLM connector, configured MCP connectors, and domains matching allowedDomains. allowedDomains accepts regexes separated by |. Default to an empty string if the user does not specify domains; if they do specify domains, work with them to build the right regex.
Optional inputs (add as needed):
# MCP connectors - only if agent needs external services
mcpConnectors:
type: array
default:
- your_github_mcp_connector # User must replace
- your_slack_mcp_connector # User must replace
ui:
component: array
input:
inputType: connector
inputConfig:
connectorTypes:
- Mcp
# Model name override - ONLY add if user explicitly requests it
modelName:
type: string
default: your_model_arn_or_id # User must replace with their model ARN or ID
# Custom parameters
repo_name:
type: string
default: my-org/my-repolayout block (always include, only list fields that are present as inputs):
The layout block controls what appears in the agent configuration UI. It contains at most four items — llmConnector, allowedDomains, modelName, and mcpConnectors — and only those that exist as first-class input fields in the inputs section. Never include any other fields (e.g. custom inputs like repo_name) in the layout block:
agent:
layout:
- title: Agent Configuration
items:
- llmConnector # always present
- allowedDomains # always present
- modelName # only if modelName input exists
- mcpConnectors # only if mcpConnectors input existsSupported input types: string, secret, boolean, connector, array
IMPORTANT: Users must create connectors via Harness UI or harness_create with resource_type="connector" before running the agent.
Assemble the complete agent YAML specification (spec field):
version: 1 and agent: structureagent.step.group.steps block with a single step entry:
name: Agent, if: <+Always>, id: agentrun.container.image: pkg.harness.io/vrvdt5ius7uwygso8s0bia/harness-agents/harness-ai-agent:latestrun.env section (all task config lives here as env vars):
PLUGIN_TASK: — multiline string with step-by-step instructions and ## RULES sectionPLUGIN_MAX_TURNS: 150 (adjust 100-200 based on complexity)PLUGIN_HARNESS_CONNECTOR: ${{inputs.llmConnector.id}}PLUGIN_ALLOWED_DOMAINS: ${{inputs.allowedDomains}}PLUGIN_MCP_FORMAT: harness (only if MCPs needed)PLUGIN_MCP_SERVERS: <+connectorInputs.resolveList(<+inputs.mcpConnectors>)> (only if MCPs needed)ANTHROPIC_MODEL: ${{inputs.modelName}} (only if user explicitly requests a modelName input)agent.inputs section with:
llmConnector (required) with ui.connectorCategories: [AI]allowedDomains (default "") to allow additional network domains using regexesmcpConnectors (optional - only if needed) with ui.component: array, ui.input.inputType: connector, and ui.input.inputConfig.connectorTypes: [Mcp]modelName (optional - only if user explicitly requests it)agent.layout block — only include items that are present as inputs:
llmConnectorallowedDomainsmodelName only if that input existsmcpConnectors only if that input existsAlways notify users to create connectors and replace placeholder IDs before running the agent.
Present the complete agent configuration to the user:
Wait for explicit confirmation before creating/updating the agent.
Only after confirmation, use harness_create to create a new agent or harness_update to update an existing one:
Call MCP tool: harness_create
Parameters:
resource_type: "agent"
org_id: "<organization>"
project_id: "<project>"
body: {
uid: "<generated_from_agent_name>",
name: "<Agent Display Name>",
description: "<Brief description of agent purpose>",
spec: "<agent YAML spec as a string>",
wiki: "<optional: markdown documentation>"
}Key fields for creation:
uid (required): Unique identifier. Always generate from name as ca_<slug> and send explicitly (e.g. "Code Coverage Agent" → ca_code_coverage_agent). Do not omit it or rely on API-side auto-generation.name (required): Display name for the agentdescription (optional): Brief descriptionspec (required): The full agent YAML specification as a string (includes version: 1, agent:, agent.step.group.steps, agent.inputs, and agent.layout)wiki (optional): Markdown documentation for the agentCall MCP tool: harness_update
Parameters:
resource_type: "agent"
resource_id: "<agent_identifier>"
org_id: "<organization>"
project_id: "<project>"
body: {
name: "<Updated Display Name>", # optional
description: "<Updated description>", # optional
spec: "<updated agent YAML spec>", # optional
wiki: "<updated markdown docs>" # optional
}Key notes for updates:
spec field replaces the entire agent specification when providedharness_get first to retrieve the current agent configuration before updatingversion: 1
agent:
step:
group:
steps:
- name: Agent
if: <+Always>
id: agent
run:
container:
image: pkg.harness.io/vrvdt5ius7uwygso8s0bia/harness-agents/harness-ai-agent:latest
env:
PLUGIN_TASK: |
Review the pull request for repository ${{inputs.repo_name}} on branch ${{inputs.branch}}.
1. Analyze code changes for security vulnerabilities
2. Check for code quality issues
3. Verify test coverage
4. Post review comments using GitHub MCP tools
## RULES
- Focus on critical security issues first
- Be constructive in feedback
- Suggest specific code improvements
PLUGIN_MAX_TURNS: 150
PLUGIN_HARNESS_CONNECTOR: ${{inputs.llmConnector.id}}
PLUGIN_ALLOWED_DOMAINS: ${{inputs.allowedDomains}}
PLUGIN_MCP_FORMAT: harness
PLUGIN_MCP_SERVERS: <+connectorInputs.resolveList(<+inputs.mcpConnectors>)>
inputs:
llmConnector:
type: connector
required: true
default: your_llm_connector_id # User must replace with actual connector ID
ui:
connectorCategories:
- AI
allowedDomains:
type: string
default: ""
mcpConnectors:
type: array
default:
- your_github_mcp_connector # User must replace with actual connector ID
ui:
component: array
input:
inputType: connector
inputConfig:
connectorTypes:
- Mcp
repo_name:
type: string
default: my-org/my-repo
branch:
type: string
default: main
layout:
- title: Agent Configuration
items:
- llmConnector
- allowedDomains
- mcpConnectorsOnce an agent is created, it is published as a template and can be used in pipelines. The agent can be referenced in both v0 and v1 pipeline YAML formats.
In v1 pipelines, the agent template exposes its custom inputs (excluding llmConnector and mcpConnectors, which are handled internally).
Example: Using Code Review Agent in a v1 Pipeline
Assuming you created a "Code Review Agent" with custom inputs repo_name and branch:
pipeline:
identifier: code_review_pipeline
name: Code Review Pipeline
inputs:
repo_name:
type: string
default: my-org/my-repo
branch:
type: string
default: feature/new-feature
stages:
- name: Code Review
steps:
- name: review_pr
template:
uses: ca_code_review_agent@1.0.0
with:
repo_name: <+inputs.repo_name>
branch: <+inputs.branch>Key points:
inputs: section defines runtime parametersuses: <agent_uid>@<version> references the published agent templatewith: block provides values for the agent's custom inputs using <+inputs.variableName> syntaxllmConnector and mcpConnectors are configured at the agent level by defaultmodelName is optional — only present in the agent if the user explicitly requested itllmConnector (and modelName if it exists) at the pipeline level if neededrepo_name, branch, thresholds, etc.) are passed in the pipelineIn v0 pipelines, agents are referenced using the Agent step type, which internally references the v1 template. The step expands the v1 template and converts it to a v0 Run Step.
Example: Using Code Review Agent in a v0 Pipeline
pipeline:
stages:
- stage:
type: Deployment
spec:
execution:
steps:
- stepGroup:
stepGroupInfra:
type: KubernetesDirect
steps:
- step:
type: Agent
name: ReviewPRAgent
identifier: ReviewPRAgent
spec:
agentName: ca_code_review_agent
agentSettings: |-
{
"repo_name": "my-org/my-repo",
"branch": "feature/new-feature",
"llmConnector": "your_llm_connector_id",
"modelName": "your_model_arn_or_id",
"mcpConnectors": ["your_github_mcp_connector", "your_slack_mcp_connector"]
}
llmConnector: your_llm_connector_id
mcpConnectors:
- your_github_mcp_connectorKey fields explained:
type: Agent - Step type for v0 pipelines that references a v1 agent templatename (required) - Display name for the step in the pipeline UIidentifier (required) - Unique identifier for the step within the pipelineagentName (required) - The agent's UID (v1 template identifier) created via harness_createagentSettings (optional) - JSON string containing template inputs for the agent:
repo_name, branch, thresholds, etc.modelName inputllmConnector (optional) - First-class field to specify LLM connector ID at pipeline levelmcpConnectors (optional) - First-class array field to specify MCP connector IDs at pipeline levelPrecedence rules:
agentSettings JSON have highest precedence - they override both agent defaults and first-class fieldsllmConnector, mcpConnectors) override agent defaultsThese are essential rules you MUST follow when creating/updating agents:
| Guideline | Rule |
|---|---|
| Check existing first | Always call harness_list(resource_type="agent") to see if an existing agent can solve the use case before creating new |
| Updating agents | Use harness_get to retrieve current config, then harness_update (not harness_create) to modify. Only custom agents can be updated. |
| Generate UID | Always derive uid as ca_<slug> (e.g. "Code Coverage Agent" → ca_code_coverage_agent) — matches platform UI nameToUid(). Pass it explicitly; do not rely on create API fallback. |
| Agent spec format | The spec field uses agent.step.group.steps structure — the run step is nested inside a named group with name: Agent, if: <+Always>, id: agent |
| Task in env | Task instructions go in PLUGIN_TASK env var (multiline string). Max turns in PLUGIN_MAX_TURNS. There is no with: block. |
| Expression syntax | Use ${{inputs.fieldName}} inside env values. Use <+connectorInputs.resolveList(...)> for MCP server resolution. |
| modelName is optional | Do NOT add modelName input or ANTHROPIC_MODEL env var by default — only add when the user explicitly requests it |
| Allowed domains | Always include PLUGIN_ALLOWED_DOMAINS: ${{inputs.allowedDomains}}, an allowedDomains string input with default "", and allowedDomains in layout. If the user specifies domains, help build the regex. |
| Input defaults | Every non-required input that is referenced via ${{inputs.fieldName}} must have a default value — omitting it causes a runtime error if the caller does not supply the value |
| Connector placeholders | Always use placeholders like your_llm_connector_id and your_mcp_connector_id and notify users to replace both LLM and MCP connector IDs with actual values before running the agent |
| No clone/platform | Do NOT add clone, platform, os, arch, or allowed_tools sections — agents are standalone with simplified structure |
| Quality first | Agent quality is paramount — verify YAML structure, validate all references, ensure complete task instructions before creating |
e554080
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.