# Use Resources with the SDK

> Declare logical needs, build model-facing Tools, and invoke accepted Resource operations with truthful effect semantics.

A Resource is a governed external capability. Definitions use logical binding names; runtime code invokes only the accepted CRN.

## Invoke directly {#invoke-directly}

```ts
const issue = await ctx.invoke<{ id: string }>(
  ctx.resources.github!,
  "issue.create",
  { owner: "acme", repository: "support", title: "Follow up" },
  { dedupeKey: `ticket:${ticketId}`, timeoutMs: 30_000 },
);
```

The operation must exist in the pinned catalog, its arguments must match the schema, and Policy must allow the exact CRN and action. Use `ctx.invokeAsync()` when the result should be a durable Handle.

## Offer the operation to a model {#offer-to-model}

```ts
import { agent, opTool } from "@constal/sdk";

const createIssue = opTool("github", "issue.create", {
  name: "create_issue",
  description: "Create one support issue.",
});

export default agent({
  id: "triage", version: "1.0.0", model: "model",
  tools: { create_issue: createIssue },
  async onMessage(message, ctx) {
    return ctx.turn({ system: "Triage support requests.", objective: message, tools: ["create_issue"] });
  },
});
```

`opTool()` is resolved against the deployment-pinned operation. For a custom `Tool`, declare a truthful `maxEffect`: read-only work may repeat, idempotent work repeats under one identity, reconcilable work needs a probe, and non-idempotent ambiguity remains outcome-unknown.

`read-only` operations may repeat, `idempotent` operations repeat with the same key, `reconcilable` operations require a probe after ambiguity, and `non-idempotent` operations surface an unknown outcome. Agent code never receives the Credential injected into a protected integration. Continue with [Build and use Tools](/docs/resources/tools.md), [Use Resources from Agents](/docs/resources/use.md), and [SDK Resource reference](/docs/sdk/resources-and-tools.md).
