> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.lakera.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.lakera.ai/_mcp/server.

# Create a Target and Scan It

The first thing you do with the SDK is turn the agent you want to test into a target,
then scan it. A target owns a recon profile — a structured description of your
application that Red uses to tailor its attacks — so creating a target is really about
deciding how that profile gets set.

This page focuses on that one decision. For the surrounding scaffolding (installing the
SDK, initializing the client, handling sessions, retrieving results), see the
[Quickstart](/docs/red/sdk-quickstart).

## Choose how the profile is set

`createOrGetTarget` finds or creates a target by name and ensures it has a recon
profile. There are three ways to provide that profile:

1. **Pass `appContext`** — supply the profile directly as a structured object. No recon
   runs.
2. **Pass `appContextFile`** — load the same profile from a YAML file. No recon runs.
3. **Pass a handler and omit the context** — the SDK runs a short reconnaissance phase,
   relaying prompts through your agent, and saves the discovered profile on the target.

A profile you pass with `appContext` or `appContextFile` always wins — it overwrites
whatever the target already held. Only when you omit the context does an existing
profile (from a previous run or the dashboard) get reused.

> **Note**
>
> Reusing an existing target by its id, rather than by name, is covered in [Reuse a Target Across Scans](/docs/red/sdk-how-tos/reuse-a-target).

## Provide the profile directly

Use this when you already know how to describe your application. It is the most
predictable option — no recon phase, so target creation returns immediately.

#### TypeScript

```typescript
const target = await client.createOrGetTarget({
  name: "my-agent",
  appContext: {
    appDescription:
      "A customer support chatbot that can look up orders and process refunds",
    allowedActions: [
      "Look up order status",
      "Process refunds",
      "Answer product questions",
    ],
    forbiddenActions: ["Reveal internal pricing rules", "Share other customers' data"],
  },
})
```

Or load the same profile from a YAML file:

```typescript
const target = await client.createOrGetTarget({
  name: "my-agent",
  appContextFile: "./app-context.yaml",
})
```

#### Python

```python
from lakera_red_sdk import ReconContext

target = await client.create_or_get_target(
    "my-agent",
    app_context=ReconContext(
        app_description="A customer support chatbot that can look up orders and process refunds",
        allowed_actions=["Look up order status", "Process refunds", "Answer product questions"],
        forbidden_actions=["Reveal internal pricing rules", "Share other customers' data"],
    ),
)
```

Or load the same profile from a YAML file:

```python
target = await client.create_or_get_target("my-agent", app_context_file="./app-context.yaml")
```

## Let recon discover the profile

Use this when you'd rather have Red build the profile for you. Omit the context and pass
a handler — the same handler signature you use for `scan.run`. Recon relays a few
prompts through your agent and saves the result on the target.

#### TypeScript

```typescript
const target = await client.createOrGetTarget({ name: "my-agent" }, async (session) => {
  for await (const { attack, respond } of session) {
    const reply = await myAgent.chat(attack)
    await respond(reply)
  }
})
```

#### Python

```python
async def handler(session):
    async for message in session:
        reply = await my_agent.chat(message.attack)
        await message.respond(reply)


target = await client.create_or_get_target("my-agent", handler=handler)
```

## Scan the target

However the profile was set, pass the returned target's `targetId` to `createScan`. The
recon profile is read from the target, so the scan needs no further context.

#### TypeScript

```typescript
const scan = await client.createScan({
  name: "CI nightly security check",
  targetId: target.targetId,
  strategy: { name: "static" },
  objectives: ["security.system-prompt-extraction.1"],
  concurrency: 5,
})

await scan.run(async (session) => {
  for await (const { attack, respond } of session) {
    const reply = await myAgent.chat(attack)
    await respond(reply)
  }
})

console.log(`View report: ${scan.dashboardLink}`)
```

#### Python

```python
from lakera_red_sdk import StaticStrategyOptions

scan = await client.create_scan(
    target.target_id,
    name="CI nightly security check",
    strategy=StaticStrategyOptions(),
    objectives=["security.system-prompt-extraction.1"],
    concurrency=5,
)


async def handler(session):
    async for message in session:
        reply = await my_agent.chat(message.attack)
        await message.respond(reply)


await scan.run(handler)

print(f"View report: {scan.dashboard_link}")
```

See [Creating a Target](/docs/red/sdk-reference#creating-a-target) in the SDK Reference
for the full parameter list.