Plural
Docs

Build a first project

This page builds a small support-triage project from empty templates. The AI reads a support ticket and sorts it into the right category, and a grader checks its answer. It ends up the same shape as the finished support queue project, so you can compare your work with it at any point.

Prefer to start from the finished project? Download it and follow the support queue tutorial instead.

You need Plural installed; see Install.

Create the project

A project is the folder that holds everything you build.

bash
plural project init support-queuecd support-queue

This works offline. It creates project.yaml, plural.lock, pyproject.toml, README.md, and a .gitignore that leaves out .plural/, where Plural keeps the records of your runs and other local state. Commit plural.lock; Plural updates it when you push.

Scaffold the resources

Each building block gets its own template. You will create five:

  • an Environment called support-queue: the world, a help desk with tickets,
  • a Verifier called correct-category: the grader, which checks the category,
  • a Task called ticket-1: one assignment, a single ticket to sort,
  • a Benchmark called support-triage: the exam, which groups the Tasks, and
  • an Agent called careful: the contestant, a model plus its instructions.
bash
plural env init support-queue --python --bareplural verifier init correct-categoryplural task init ticket-1 --environment support-queue --verifier correct-categoryplural benchmark init support-triageplural benchmark add ticket-1 --benchmark support-triageplural agent init careful --model openai/gpt-5.6-luna

Each init command writes one folder, such as environments/support-queue/ or tasks/ticket-1/, and marks every place you must fill in with PLURAL-TODO:

  • environments/support-queue/environment.py: the App. What it holds (its State), the moves it can make (its @action methods), and what each move returns, which is all the AI sees. Keep the answers on State, never in what an action returns. Mark the fields a Task sets with initial().
  • environments/support-queue/README.md: what the world is and how to use it.
  • verifiers/correct-category/verify.py: compare how things ended with what the Task asked for, and return a score from 0 to 1 with evidence.
  • tasks/ticket-1/instruction.md: what the AI must accomplish, in plain language. Set the Task's starting State under initial_state in task.yaml.
  • benchmarks/support-triage/benchmark.yaml and its README.md: the purpose, and what a score means in scoring.description.

Also write the Agent's instructions in agents/careful/agent.yaml. The Agent has no harness, so it plays with native, Plural's built-in tool loop.

The finished files in the support queue tutorial show one way to fill in each of these.

Good to know: The new Environment uses the local runtime, which runs it as a subprocess on your machine. That needs no setup, and it is not a sandbox. To keep the AI's world in a sealed container, set runtime.provider: docker; see Runtimes.

Validate and run

Check your work, preview the run, run it, and look at the result:

bash
plural benchmark validate support-triageplural run --benchmark support-triage --agent careful --dry-runplural run --benchmark support-triage --agent carefulplural job show <job-id>
  • validate checks a resource and everything it depends on, and lists every PLURAL-TODO you left unfinished. Unfinished places don't stop a local run, but push and --record refuse them.
  • --dry-run shows the plan without running anything.
  • The real run calls the model through the Plural gateway, so it needs a Plural API key (plural auth login, plural auth login --api-key-stdin, or PLURAL_API_KEY). The run prints the Job id to pass to plural job show.

To run without any credential, add a Harness that calls no model and an Agent with auth: none, like the scripted Agent in the finished project.

Next steps

To add more tickets, repeat plural task init and plural benchmark add, or list them as cases and write them all with plural task cases.

When you want to see runs in the web app, register the project with plural project init support-queue --push and add --record to plural run. The support queue tutorial covers both. Pushing never makes anything public.