-
Notifications
You must be signed in to change notification settings - Fork 1
docs(conditions): Add LLM-friendly authoring resources #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
theref
wants to merge
6
commits into
main
Choose a base branch
from
docs/conditions-llm-authoring
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
2678257
docs(conditions): Add LLM-friendly authoring resources
theref 3dc7127
docs(conditions): Remove framing that understates expressivity
theref 13fc5d5
docs(conditions): Wrap cookbook examples in version envelope
theref 771eb0f
docs(conditions): Reference auto-generated JSON Schema export
theref 5c6756d
docs(conditions): Address PR #12 review feedback
theref e366a11
docs(conditions): Add :nullAddress; refine context-var attribution
theref File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
123 changes: 123 additions & 0 deletions
123
for-developers/taco-sdk/references/conditions/building-with-llms.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| # Building Conditions with an LLM | ||
|
|
||
| TACo conditions are JSON. That makes them an excellent target for LLM-assisted authoring: describe the access policy you want in plain English, hand the LLM the right context, and iterate until the validator is happy. | ||
|
|
||
| This page is the recommended workflow. | ||
|
|
||
| ## The context you give the LLM | ||
|
|
||
| Paste these four things into your LLM of choice (Claude, ChatGPT, Cursor, etc.) at the start of a new conversation: | ||
|
|
||
| 1. **The full condition schema** — the canonical, machine-readable definition of every condition type, every field, every allowed value. Two formats are auto-generated from the same TypeScript source: | ||
| - [`condition-schemas.md`](https://github.com/nucypher/taco-web/blob/signing-epic/packages/taco/schema-docs/condition-schemas.md) — human-readable reference for prose-style LLMs. | ||
| - [`condition-schema.json`](https://raw.githubusercontent.com/nucypher/taco-web/signing-epic/packages/taco/schema-docs/condition-schema.json) — standard [JSON Schema](https://json-schema.org/) document. Use this with structured-output LLM APIs and editor `$schema` references (see [JSON Schema integration](#json-schema-integration) below). | ||
|
|
||
| Link these directly — do not vendor copies that will drift. | ||
| 2. **The cookbook** — [JSON examples covering every condition type](cookbook.md). Examples teach an LLM patterns far faster than prose. | ||
| 3. **The deep-dive** — the [Discord tipping bot walkthrough](discord-tipping-bot-deep-dive.md). One realistic, complex, fully-annotated condition is worth a thousand toy examples. | ||
| 4. **The validator script** — [`validate-conditions.ts`](validating-conditions.md). Tell the LLM it can run this and iterate on the output. | ||
|
|
||
| ## A prompt template | ||
|
|
||
| ``` | ||
| You are helping me author a TACo condition in JSON. | ||
|
|
||
| Reference material (please read before writing any condition): | ||
| - Schema (source of truth): https://github.com/nucypher/taco-web/blob/signing-epic/packages/taco/schema-docs/condition-schemas.md | ||
| - Cookbook of examples: https://docs.taco.build/for-developers/taco-sdk/references/conditions/cookbook | ||
| - Annotated complex example: https://docs.taco.build/for-developers/taco-sdk/references/conditions/discord-tipping-bot-deep-dive | ||
|
|
||
| Rules: | ||
| - Output a single JSON object (no prose around it) when I ask for a condition. | ||
| - Every field must exist in the schema. Do not invent fields. | ||
| - Context variables start with ":" and match /^:[a-zA-Z_][a-zA-Z0-9_]*$/. | ||
| - CompoundCondition: max 5 operands, max 2 levels of nesting. | ||
|
derekpierre marked this conversation as resolved.
Outdated
|
||
| - SequentialCondition: 2–20 variables. | ||
| - After each condition you produce, I will run validate-conditions.ts and | ||
| paste the output back. Fix any validation errors and try again. | ||
|
|
||
| What I want the condition to enforce: | ||
| <describe your access policy in plain English> | ||
| ``` | ||
|
|
||
| ## The iteration loop | ||
|
|
||
| 1. LLM produces a condition. | ||
| 2. Save it as `conditions.json`. | ||
| 3. Run `npx tsx validate-conditions.ts` ([source](validating-conditions.md)). | ||
| 4. If invalid, paste the error back to the LLM. If valid, test it end-to-end with the [TACo Playground](https://playground.taco.build/) or your app. | ||
|
|
||
| This loop usually converges in 1–3 rounds even for complex conditions. | ||
|
|
||
| ## Tips that materially improve LLM output | ||
|
|
||
| - **Be explicit about the chain ID.** "Base mainnet" is ambiguous to a model that has not read your config; say `"chain": 8453`. | ||
| - **Name the data source.** "Check an NFT balance" is vague. "Call `balanceOf(:userAddress)` on contract `0xabc...` on Polygon (137) and require result `> 0`" is unambiguous. | ||
| - **Specify the comparator.** Models default to `==` even when you mean `>=`. | ||
| - **For sequential conditions**, list variables in dependency order and remind the model that later variables can reference earlier ones with `:varName`. | ||
| - **For ABI validation**, give the model the function signature (e.g. `transfer(address,uint256)`) — it cannot guess parameter order reliably. | ||
| - **When using `signing-attribute` / `signing-abi-attribute`**, mention which signing object format you are using (UserOperation, plain transaction, custom struct) so the model picks the right `attributeName`. | ||
|
|
||
| ## JSON Schema integration | ||
|
|
||
| The auto-generated [`condition-schema.json`](https://raw.githubusercontent.com/nucypher/taco-web/signing-epic/packages/taco/schema-docs/condition-schema.json) is the highest-leverage piece of tooling available for condition authoring. It works in three places without any TACo dependency: | ||
|
|
||
| ### Editors | ||
|
|
||
| Add `$schema` to the top of any `conditions.json` and your editor (VS Code, Cursor, JetBrains) will validate it inline as you type, with autocomplete for every field: | ||
|
|
||
| ```json | ||
| { | ||
| "$schema": "https://raw.githubusercontent.com/nucypher/taco-web/signing-epic/packages/taco/schema-docs/condition-schema.json", | ||
| "version": "1.0.0", | ||
| "condition": { | ||
| "conditionType": "time", | ||
| "chain": 137, | ||
| "method": "blocktime", | ||
| "returnValueTest": { "comparator": ">", "value": 1735689600 } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### LLM structured output | ||
|
|
||
| Both Anthropic and OpenAI's APIs accept a JSON Schema directly to constrain model output. Example with the Anthropic SDK: | ||
|
|
||
| ```ts | ||
| import Anthropic from '@anthropic-ai/sdk'; | ||
|
|
||
| const conditionSchema = await fetch( | ||
| 'https://raw.githubusercontent.com/nucypher/taco-web/signing-epic/packages/taco/schema-docs/condition-schema.json' | ||
| ).then(r => r.json()); | ||
|
|
||
| const result = await new Anthropic().messages.create({ | ||
| model: 'claude-opus-4-6', | ||
| max_tokens: 2048, | ||
| tools: [{ | ||
| name: 'emit_condition', | ||
| description: 'Emit a TACo condition matching the requested policy.', | ||
| input_schema: conditionSchema, | ||
| }], | ||
| tool_choice: { type: 'tool', name: 'emit_condition' }, | ||
| messages: [{ | ||
| role: 'user', | ||
| content: 'Build a condition that allows decryption only if the requester holds at least one NFT from collection 0xabc on Ethereum mainnet.', | ||
| }], | ||
| }); | ||
| ``` | ||
|
|
||
| The model is now structurally constrained — it cannot return invalid shapes. | ||
|
|
||
| ### Standalone validation (any language) | ||
|
|
||
| You no longer need `@nucypher/taco` installed to validate. Any standard JSON Schema validator works: | ||
|
|
||
| ```bash | ||
| pnpm dlx ajv-cli validate \ | ||
| -s https://raw.githubusercontent.com/nucypher/taco-web/signing-epic/packages/taco/schema-docs/condition-schema.json \ | ||
| -d conditions.json --strict=false | ||
| ``` | ||
|
|
||
| The Python equivalent uses [`jsonschema`](https://python-jsonschema.readthedocs.io/), the Go equivalent uses [`gojsonschema`](https://github.com/xeipuuv/gojsonschema), etc. | ||
|
|
||
| The `validate-conditions.ts` script ([page](validating-conditions.md)) is still useful when you want runtime semantics (e.g. catching nesting-depth errors that JSON Schema cannot express), but for shape validation alone the JSON Schema is enough. | ||
87 changes: 87 additions & 0 deletions
87
for-developers/taco-sdk/references/conditions/context-variables.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # Context Variables Cheatsheet | ||
|
|
||
| A **context variable** is a placeholder used inside a condition. Its value is supplied at decryption (or signing) time, not at encryption time. That is what makes a single encrypted ciphertext usable across many requesters and many runtime states. | ||
|
|
||
| This page is a cheatsheet. For a longer narrative, see [Condition Context](../authentication/conditioncontext-and-context-variables.md). | ||
|
|
||
| ## Naming rules | ||
|
|
||
| - Always start with `:` — e.g. `:userAddress` | ||
| - After the `:`, the name must match `/^[a-zA-Z_][a-zA-Z0-9_]*$/` | ||
| - Case-sensitive | ||
| - No dots, dashes, or spaces. `:user-address`, `:user.address`, `:1stParam` are all invalid. | ||
|
|
||
| If you forget the leading `:`, the SDK will treat your value as a literal string and your condition will silently match nothing (or worse, match something). | ||
|
|
||
| ## Built-in context variables | ||
|
|
||
| These are automatically populated by the SDK or by the network. You do **not** need to set them yourself. | ||
|
derekpierre marked this conversation as resolved.
Outdated
|
||
|
|
||
| | Variable | Set by | Available in | Description | | ||
| | :--- | :--- | :--- | :--- | | ||
| | `:userAddress` | Decrypter's wallet | All conditions | The Ethereum address of the requester. Replaced after the requester signs an authentication message. | | ||
| | `:message` | Decrypter | `EcdsaCondition` | The message that was signed. Default for `EcdsaCondition.message`. | | ||
| | `:signature` | Decrypter | `EcdsaCondition` | The signature being verified. Default for `EcdsaCondition.signature`. | | ||
| | `:jwtToken` | Decrypter | `JwtCondition` | The JWT being validated. Default for `JwtCondition.jwtToken`. | | ||
| | `:signingConditionObject` | Signing flow | `SigningObjectAttributeCondition`, `SigningObjectAbiAttributeCondition` | The full object (e.g. UserOperation) being submitted for threshold signing. | | ||
|
|
||
| ## Custom context variables | ||
|
|
||
| You can define any name you like, as long as it follows the [naming rules](#naming-rules). The decrypter is responsible for supplying its value at decryption time. | ||
|
|
||
| ```json | ||
| { | ||
| "conditionType": "json", | ||
| "data": ":discordPayload", | ||
| "query": "$.member.user.id", | ||
| "returnValueTest": { "comparator": ">", "value": 0 } | ||
| } | ||
| ``` | ||
|
|
||
| Here `:discordPayload` is a custom variable. The bot supplies it as part of the decryption request. | ||
|
|
||
| ### Variables produced by SequentialCondition | ||
|
|
||
| `SequentialCondition` lets each step bind a `varName`. That name becomes a context variable usable by subsequent steps: | ||
|
|
||
| ```json | ||
| { | ||
| "conditionType": "sequential", | ||
| "conditionVariables": [ | ||
| { | ||
| "varName": "balance", | ||
| "condition": { "...": "fetches an ERC20 balance" } | ||
| }, | ||
| { | ||
| "varName": "validate", | ||
| "condition": { | ||
| "conditionType": "context-variable", | ||
| "contextVariable": ":balance", | ||
| "returnValueTest": { "comparator": ">=", "value": 1000 } | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| `varName` is a **plain string** (no leading `:`), but you reference it later **with** the `:` prefix. | ||
|
|
||
| ## Where context variables can appear | ||
|
|
||
| | Field type | Accepts context variable? | | ||
| | :--- | :--- | | ||
| | `returnValueTest.value` | ✅ | | ||
| | `ContractCondition.parameters[*]` | ✅ | | ||
| | `JsonCondition.data` | ✅ (required — must be a context variable) | | ||
| | `JsonCondition.query` | ✅ (or a JSONPath) | | ||
| | `JsonApiCondition.endpoint` | ❌ (must be a literal HTTPS URL) | | ||
| | `JsonApiCondition.authorizationToken` | ✅ | | ||
| | `EcdsaCondition.message` / `signature` | ✅ | | ||
| | `JwtCondition.jwtToken` | ✅ | | ||
| | `chain`, `method`, `comparator` | ❌ — must be literal | | ||
| | ABI function signature keys (`"transfer(address,uint256)"`) | ❌ — must be literal | | ||
| | ABI parameter `value` inside `returnValueTest` | ✅ | | ||
|
|
||
| ## Common gotcha: JSONPath vs context variable | ||
|
|
||
| `JsonCondition.query` accepts **either** a JSONPath expression (`$.member.user.id`) **or** a context variable (`:somePath`). The schema disambiguates by the leading character — `$` means JSONPath, `:` means context variable. Anything else is a validation error. | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.