I recently read a post published by Perplexity titled Rethinking Search as Code Generation. The post describes Perplexity’s move toward a search process built specifically for agents. Their argument is that search should no longer be treated as a single, fixed service that agents repeatedly call. Instead, it should be exposed as a programmable collection of retrieval primitives.
The idea is that modern agents need control over the entire retrieval process, not merely the query. By generating code, an agent can parallelize hundreds or thousands of searches, inspect intermediate results, filter and aggregate them deterministically, adapt its strategy, and pass only the most useful evidence back into model context.
I think Perplexity’s Search as Code (SaC) approach is best understood as one example of a much larger shift in agent architecture. Today, when agents use workflows, those workflows are usually designed by developers in advance, either surrounding the agent or exposed to it as high-level tools. In the approach I’m calling Work as Code (WaC), developers instead provide a stable runtime, composable primitives, and clear operating boundaries. The model interprets the goal and generates the task-specific program that combines those primitives. The model provides interpretation and judgment, while code handles control flow, parallelism, state, and deterministic execution. In that world, an agent does not simply use software; it creates the software required to perform the work just in time.
At first, this may sound similar to ideas such as personal software or throwaway software. Those ideas are closely related, but they focus on different properties of the resulting software.
The defining property of Work as Code is therefore not who the software serves or how long it survives. It is how the software is assembled. You provide the agent with a stable runtime, a set of composable primitives, and boundaries within which it may operate. The agent then translates your intent into a program that determines how those primitives should be combined.
That program could be temporary or persistent, personal or shared. Those are lifecycle and distribution choices. They do not define the architecture itself. What defines the architecture is that the workflow is composed dynamically from primitives instead of being authored completely in advance.
This places Work as Code somewhere between two common approaches to building agentic systems. At one end is the free-form agent loop: a model receives instructions and a small set of primitive tools, such as a CLI and the ability to write code, and is largely left to determine how the work should be completed. At the other end is an “agent” wrapped inside a deterministic, developer-authored workflow. Both approaches have tradeoffs, though I won’t explore them here.
Work as Code occupies the space between them. The model owns the strategy, reasoning, and composition, while delegating execution to deterministic code. The resulting program is dynamic at the level of planning and composition but structured at the level of execution.
How Perplexity Built Search as Code
What Perplexity built is more involved than taking its existing search API and making it callable from Python. They first broke their search stack into smaller operations they call primitives. These include operations such as retrieval, ranking, filtering, fan-out, rendering, and semantic parsing. Their higher-level search pipelines are still available, but an agent can reach for the lower-level pieces when a task requires more control.
Perplexity then brought together three parts of the system. The model interprets the request, works out a search strategy, and generates the code needed to carry it out. That code runs inside a secure sandbox, which provides the deterministic runtime for loops, parallel requests, retries, joins, filtering, deduplication, and aggregation. The Agentic Search SDK is the third part. It gives the generated program direct access to the individual capabilities inside Perplexity’s search stack.
This division of labor is what makes the approach useful. The model can focus on deciding how the search should work, while ordinary code handles the repetitive mechanics. Instead of returning to the model after every search operation, a single program can perform hundreds or thousands of operations within one inference turn and return only the evidence worth reasoning about.
The generated code can also fill gaps between the capabilities provided by the SDK. Perplexity uses complex filtering as an example. The agent can retrieve a broad set of candidates through the SDK and then write its own deterministic filtering logic to narrow those results. This means the SDK does not need a dedicated function for every operation an agent might eventually need.
The sandbox is also doing more than executing code. It has to manage the intermediate state produced by these longer workflows. Perplexity tested both a persistent REPL, where variables remain available across turns, and explicit serialization through a persistent filesystem. The REPL was more token-efficient, but the filesystem proved more reliable across longer trajectories because it forced the model to explicitly record which state needed to survive. Perplexity ultimately chose the filesystem approach.
However, exposing an SDK to a model does not mean the model automatically knows how to use it well. The SDK was new, so models would not have encountered it during training. Source code and generated documentation could explain what each function did, but not necessarily how to combine those functions into an effective search strategy.
To close that gap, Perplexity created compact Agent Skills containing guidance and examples that showed models how to compose the available primitives. The point of the Skills was not to list every function. The model could discover those through the runtime. Instead, the skills taught reusable patterns for building search pipelines. Perplexity then used separate autoresearch loops to improve the SDK and the Skills by measuring latency, code-generation quality, and final task performance.
You can see these pieces working together in Perplexity’s CVE example Case Study: CVE Vendor Advisories. The generated program first fans out across vendor-specific advisory formats. It then measures where its coverage is weak, asks a model to propose targeted searches for those gaps, validates the proposed queries, and runs them in parallel. Finally, it uses structured extraction and deterministic filtering to verify that each CVE is tied to a specific product and fix version in a vendor-authored advisory.
Taken together, this shows that Perplexity was not simply giving the model more tools. It was designing the search primitives, SDK, execution environment, state model, and instructions as parts of the same system. Each part gives the model a different kind of control, allowing it to turn a search strategy into a task-specific program without forcing the entire process through model context.
Building the Work as Code Architecture
If you want to take this idea beyond search, the broader opportunity is to apply this pattern to work itself. To do so, you must first ask yourself, “What parts of work can I make available as building blocks that an agent can assemble differently for each task?”
Picture yourself as the person responsible for investigating why a product missed its quarterly forecast. Answering that question might require comparing actuals sales against the forecast, breaking the variance down by customer and region, reviewing pricing changes, checking delayed deals, examining inventory or delivery issues, and reading notes from the teams involved. You could attempt to build a deterministic workflow upfront, but the next request may involve a different product, customer, set of parameters, or type of analysis. This makes the process difficult to define in advance because each finding may determine what should be examined next. Work as Code allows the agent to generate the analysis process required by the evidence it encounters and adjust that process as new information becomes available.
With Work as Code, you expose the underlying capabilities and allow the model to generate the program needed for the particular request. Those capabilities might include reading and writing documents, retrieving business records, querying databases, invoking approved actions in external systems, or asking another model to interpret something ambiguous. Together, they become a vocabulary the agent can use to express how work should be completed.
The first thing you’ll need to do is choose the right boundaries. A function such as analyze_performance_variance() could apply the same predefined analysis workflow to many situations, and it may still be useful as a shortcut for common requests. However, it should not be the agent’s only option because it hides most of the strategic decisions inside the function. If you also provide primitives such as get\_sales\_data(), get\_forecast\_data(), get\_pricing\_changes(), get\_deal\_status(), match\_entities(), and classify\_evidence(), the agent has enough control to construct a review appropriate to the situation. At the same time, you probably don’t want to expose every database query and HTTP request as a separate capability. The useful boundary is somewhere between those extremes. Each operation should be reliable and meaningful on its own while remaining composable in ways you did not anticipate.
To make these capabilities work in a real setting, they should return structured data rather than prose wherever possible, behave predictably when something fails, and make it easy to process many records at once. That allows ordinary code to handle repetitive tasks such as filtering, joining, calculating, validating, and retrying, while the model concentrates on interpreting the request and deciding what the program should do. Any action that changes a business record should go through an explicit capability with its own permissions and validation.
Once those capabilities have been designed for code, the next question is where that code actually runs. The execution environment gives the generated program access to approved capabilities while controlling credentials, data access, execution time, concurrency, and cost. It can treat reading and writing as separate permissions, require approval for sensitive actions, and retain intermediate artifacts so the work remains inspectable. The model can inspect those artifacts and decide whether it has enough evidence or needs to generate another stage of the program. If the agent produces a recommendation or changes a business record, you should be able to see what information it used and which operations led to that result.
Giving the model safe access to those capabilities only solves the execution side of the problem. It still needs to understand how the pieces fit together within your particular working environment. API documentation can explain what each capability does, but it rarely explains how to combine them effectively. A small set of instructions and examples can provide that missing context by demonstrating common patterns, important business rules, useful validation steps, and situations that require additional judgment. The goal isn’t to prescribe every workflow. It’s to give the model enough understanding to create an appropriate one.
Provide context, not rigid instruction A small set of instructions and examples can provide the missing context by demonstrating common patterns, important business rules, useful validation steps, and situations that require additional judgment. The goal isn't to prescribe every workflow. It's to give the model enough understanding to create an appropriate one.
The guidance is only useful if the model can apply it to real work. To find out, evaluate the system using the kinds of requests people will actually make. These might include reconciling inconsistent records, reviewing agreements, preparing an analysis, updating a project, or creating a decision-ready deliverable. Judge whether the completed work is correct, complete, traceable, safe, and useful. The exact program matters less than whether it produces the intended outcome reliably, follows its permissions, leaves a clear record of what it did, and operates at a reasonable cost.
Over time, as you evaluate the system across more requests, recurring patterns will begin to emerge. Some stable operations may deserve to become reusable capabilities of their own or higher-level shortcuts for common work. Others will remain specific to a single request and disappear when the work is finished. This is central to Work as Code. Developers create a dependable foundation for doing work, while the agent turns that foundation into software for the task at hand.
