Files
scriptorium/docs/roadmap/library.md

177 lines
9.8 KiB
Markdown

# Library API Production Roadmap
This roadmap defines the target state for making Scriptorium's public Go package production-ready for downstream applications while preserving the existing CLI and HTTP behavior.
The library remains an additional adapter surface. It should not replace the subprocess, CLI, or HTTP contracts that already exist.
## Motivation
Many Go applications can use Scriptorium more cleanly as an imported package than as a subprocess. A downstream developer should be able to keep prompt assets in standard Scriptorium format, pass application data through a small adapter, and receive a typed response without reimplementing prompt rendering, profile resolution, validation, or OpenAI-compatible request construction.
The core consumer story is:
- the downstream app owns one or more `prompt.yml` files in standard Scriptorium format;
- those prompts may use inline content, `content_file` references, variables, cache-control markers, and structured-output schemas;
- the app may provide its own `profile.yml`, or select a standard built-in/profile-template configuration;
- the app supplies an API key as a normal Go value when the selected profile requires one;
- the app calls the public Go package to prepare or run the request and receives typed results.
## Current State
The public package already provides the first library facade:
- root package import;
- typed engine construction;
- typed prepare/run requests and results;
- file and inline artifact references;
- execution overrides;
- custom LLM injection for testing or alternate execution;
- public error categories that map internal failures to stable caller-facing errors.
The remaining production-readiness gaps are mostly about consumer ergonomics and asset sourcing:
- callers are still oriented around filesystem prompt/profile/schema directories;
- embedded prompt/profile/schema assets are not a first-class public use case;
- standard or built-in profile selection is not yet available;
- library credential supply is still tightly coupled to environment-variable lookup rather than direct API-key values;
- public documentation and examples need to show the intended downstream app adapter pattern.
## Target State
The public package should let a downstream Go application use standard Scriptorium assets without temporary directories, subprocess invocation, or internal package imports.
### Prompt Assets
The library should support prompt definitions from:
- existing prompt directories;
- a single prompt file;
- `fs.FS`, including `embed.FS`.
Prompt syntax should remain the standard Scriptorium prompt YAML format. `content_file` references should continue to be supported and should resolve relative to the prompt definition's source location within the same asset source.
The public API should not introduce a separate in-code prompt DSL as the primary path. YAML remains the canonical authoring format so prompts can be shared between CLI, HTTP, subprocess, and library usage.
### Schema Assets
Structured-output schemas should be loadable from the same kinds of sources as prompt definitions:
- existing schema directories;
- a single schema file where appropriate;
- `fs.FS`, including `embed.FS`.
Schema references should retain the existing prompt-format semantics. A schema referenced by a prompt should resolve through the configured schema source, not through ad hoc caller code.
### Profile Assets
The library should support both custom and standard profile configuration:
- existing profile directories;
- a single profile file;
- `fs.FS`, including `embed.FS`;
- direct public profile values for applications that already have profile configuration in memory;
- built-in/profile-template helpers for common OpenAI-compatible targets.
Custom profiles and built-in/template profiles should flow through the same internal profile resolution and request-construction path. The built-in path should not become a separate execution mode.
### Built-In Profile Templates
Built-in support should favor stable profile templates over a large registry of fixed model IDs.
For example, the public package should make it easy to construct or select an OpenAI-compatible profile by supplying the durable parts of the profile:
- profile ID or name;
- base URL;
- model;
- whether the profile requires an API key;
- default numeric parameters where desired;
- structured-output and extra-parameter behavior consistent with normal profiles.
The package may include a small set of named helpers for common OpenAI-compatible services, but those helpers should avoid hard-coding a broad and fast-changing list of model names.
### Credentials
The public package must keep raw API keys out of prompt/profile YAML, prepared-run output, run results, logs, and examples.
For the public library API, the single supported credential-supply method should be a direct API-key value passed by the consuming Go application. The consuming application is responsible for loading and managing its own secrets before calling Scriptorium.
This may be exposed as a field such as `Config.APIKey`, an option such as `WithAPIKey`, or an equivalent request/engine-level value that is easy to pass through an application adapter. The exact API should avoid accidental serialization in prepared output, run results, logs, and examples.
The public package should not encourage raw API-key storage in prompt/profile YAML. Existing CLI behavior may continue to use environment-variable references for compatibility, but the production library path should not introduce a separate credential resolver or secret-manager abstraction.
### Public API Shape
The public API should remain narrow, idiomatic, and stable. Recommended additions include:
- engine options for prompt/profile/schema directories;
- engine options for prompt/profile/schema `fs.FS` sources;
- engine options for single prompt/profile/schema files where useful;
- public profile/template constructors that map to internal profile definitions;
- a direct API-key value for profiles that require authentication;
- examples showing `embed.FS`, custom profile files, template profile selection, and fake LLM testing.
The public package should continue to expose facade types rather than exporting internal package types. Internal package layout should remain free to evolve.
## Scope
In scope:
- first-class `fs.FS` support for public library prompt, profile, and schema sources;
- ergonomic single-file asset options where they reduce caller boilerplate;
- built-in/profile-template helpers for common OpenAI-compatible usage;
- in-memory public profile values where appropriate;
- direct API-key value support for the public library path;
- consumer-facing examples under `examples/`;
- consumer package documentation under `docs/consumers/` once behavior is implemented;
- tests proving library behavior matches existing CLI/use-case behavior.
Out of scope:
- changing standard prompt, profile, or schema file formats;
- exposing internal packages as public API;
- replacing or removing CLI, HTTP, or subprocess support;
- adding a multi-step workflow engine;
- adding non-Go bindings;
- maintaining a comprehensive provider/model catalog;
- accepting raw API keys in serialized YAML/JSON configuration;
- adding a credential resolver or secret-manager abstraction.
## Acceptance Criteria
- A Go caller can import the root package and run a standard Scriptorium prompt without invoking a subprocess.
- A Go caller can use prompt definitions from `embed.FS`, including prompts with `content_file` references.
- A Go caller can use structured-output schemas from `embed.FS` or filesystem sources.
- A Go caller can provide a custom profile from filesystem, `fs.FS`, or public in-memory profile values.
- A Go caller can select a standard OpenAI-compatible profile template without writing a full profile file.
- A Go caller can supply an API key as a normal Go value without raw secrets appearing in serialized config, prepared output, or results.
- Public library behavior remains consistent with CLI/HTTP semantics for rendering, validation, profile resolution, runtime overrides, structured output, cache control, and LLM invocation.
- Existing CLI and HTTP behavior remains unchanged.
- Library tests use fake or local LLM boundaries and do not require real provider credentials.
- Public docs outside `docs/roadmap/` describe only implemented behavior after the feature is built.
## Design Decisions
### Asset Source API
Add first-class `fs.FS` options for prompt, profile, and schema sources while keeping existing directory-based configuration. Also add single-file convenience options where they remove meaningful caller boilerplate. Resolve `content_file` references relative to the prompt file's location inside the same source.
Reasoning:
This is the most idiomatic path for production Go libraries because it supports `embed.FS`, `os.DirFS`, tests, and in-memory fixture files through the same abstraction. It also avoids requiring downstream applications to unpack embedded assets into temporary directories.
### Built-In Profile Strategy
Provide stable profile-template helpers for OpenAI-compatible endpoints rather than a broad registry of fixed provider/model profiles. Let callers choose the model and endpoint where those values are service-specific or fast-changing.
Reasoning:
Endpoint shape and credential mechanics are relatively stable; model catalogs change frequently. Templates give consumers a short, correct path without making Scriptorium responsible for tracking every provider's model list.
### In-Memory Profile Values
Expose a small public profile facade type for in-memory profile configuration and map it to internal profile definitions. Keep it intentionally aligned with the existing profile YAML contract.
Reasoning:
Many applications already hold configuration in typed structs and should not need to generate YAML files just to call Scriptorium. A public facade keeps internal types private while making the library practical for production use.