Add framework documentation and offline example

This commit is contained in:
2026-07-28 04:53:51 +00:00
parent e4899fb54d
commit 9e68a2bbf7
15 changed files with 454 additions and 68 deletions

View File

@@ -11,8 +11,21 @@ The root `promptkit` package provides the supported public engine. Consumers
can configure filesystem or in-memory prompt, profile, and schema sources,
prepare requests without generation, run requests with the built-in
OpenAI-compatible client, or inject their own model client and artifact reader.
See the [Go package consumer guide](docs/consumers/pkg-promptkit.md) for the
public workflow and contract.
## Quickstart
Run the maintained offline preparation example from the repository root:
```sh
go run ./examples/go-library/prepare
```
It loads a repository-local prompt, supplies an in-memory profile and inline
input, and prints deterministic preparation metadata without contacting a
provider or requiring credentials. Read the
[example source](examples/go-library/prepare/main.go), the
[Go package consumer guide](docs/consumers/pkg-promptkit.md), and the
[framework format reference](docs/formats.md) to build a consumer workflow.
Contributors should start with the [development guide](docs/development.md).
The [architecture policy](docs/policy/architecture.md) defines the library

View File

@@ -9,7 +9,8 @@ import "gitea.maximumdirect.net/eric/promptkit"
Package `promptkit` is the supported Go contract for in-process prompt
preparation and execution. The declarations and their GoDoc in the
[root package](../../doc.go) own the exact API; this guide explains how the
pieces are used together.
pieces are used together. The [framework format reference](../formats.md) owns
prompt, profile, and schema file contracts.
## Engine Construction And Sources
@@ -32,10 +33,9 @@ The [source options](../../engine.go) replace their matching directory source:
- `WithLLMClient` replaces the built-in model client; and
- `WithArtifactReader` replaces the default reader for every input.
Prompt-content and schema paths from an `fs.FS` stay within the configured
root. Single-file prompt and profile sources select definitions by YAML ID.
Relative prompt content resolves from its prompt file, while a single schema
is addressed by its base name.
Source selection, path resolution, strict decoding, profile overlays, and
file-to-request precedence are defined in the
[framework format reference](../formats.md).
Per-generation timeout values from profiles or requests are independent of
the transport cap and caller context. An explicit request value of zero
@@ -49,28 +49,10 @@ defines the complete timeout layering.
[`RunRequest`](../../types.go). `Prepare` resolves the prompt, profile, input
artifacts, validation contract, and rendered messages without calling an LLM.
`Run` performs the same preparation, calls the configured client, and validates
the generated content.
```go
engine, err := promptkit.NewEngine(promptkit.Config{
PromptDir: "./prompts",
ProfileDir: "./profiles",
})
if err != nil {
return err
}
prepared, err := engine.Prepare(ctx, promptkit.RunRequest{
PromptID: "meeting.summary",
Inputs: map[string]promptkit.ArtifactRef{
"transcript": promptkit.File("./transcript.md"),
},
})
if err != nil {
return err
}
_ = prepared.Messages
```
the generated content. The maintained
[offline preparation example](../../examples/go-library/prepare/main.go)
provides a complete runnable workflow using a prompt file, in-memory profile,
and inline input.
[`PreparedRun` and `RunResult`](../../types.go) expose copied public values.
Preparation returns effective settings, hashes, rendered messages, selected
@@ -86,8 +68,10 @@ returns an error matching `ErrValidation`.
The [request and value declarations](../../types.go) own the available fields,
serialized constants, and result shapes. Use `File`, `Inline`, or
`InlineWithURI` to construct artifact references. Required declared inputs and
every input referenced by a template must be supplied.
`InlineWithURI` to construct artifact references. The
[framework format reference](../formats.md) defines declared inputs, template
references, output contracts, and the relationship between file values and
request overrides.
`ExecutionTargetOverride` uses pointers for numeric settings so an explicit
zero remains distinct from no override. `ExtraParams` accepts JSON-compatible
@@ -110,7 +94,9 @@ precedence over explicit file sources and built-ins.
Raw API keys do not belong in profiles. File-backed profiles may name an
environment variable, while an in-memory profile can require a request key.
A direct `RunRequest.APIKey` is request-scoped and takes precedence over an
environment lookup for the built-in client.
environment lookup for the built-in client. Profile fields, ranges, built-ins,
precedence, and credential rules are owned by the
[framework format reference](../formats.md).
API keys are excluded from JSON, prepared values, and results. The public
`String` and `GoString` methods report only whether a direct key is present.

View File

@@ -31,11 +31,14 @@ Start with:
| Task | Read before changing |
| --- | --- |
| Documentation or examples | The [documentation policy](policy/documentation.md) and the canonical owner of the affected contract. |
| Tests or test fixtures | The [testing policy](policy/testing.md), the owning package, and any focused internal document listed by the component overview. |
| Root public API, once implemented | The [architecture policy](policy/architecture.md), [root package declaration](../doc.go), [testing policy](policy/testing.md), and existing GoDoc. |
| Internal package implementation, once introduced | The [architecture policy](policy/architecture.md), [internal component overview](internal/overview.md), and any focused internal document that the overview lists for that package. |
| Integration behavior, once introduced | The [architecture policy](policy/architecture.md), [documentation policy](policy/documentation.md), and the integration's owning contract under `docs/integrations/`. |
| Root public API | The [architecture policy](policy/architecture.md), [consumer guide](consumers/pkg-promptkit.md), [testing policy](policy/testing.md), and existing GoDoc. |
| Prompt, profile, or schema formats | The [framework format reference](formats.md), owning parser or validator package, and [documentation policy](policy/documentation.md). |
| Source loading or validation | The [framework format reference](formats.md), [internal source document](internal/sources.md), and owning package tests. |
| Model-client behavior | The [OpenAI-compatible integration contract](integrations/openai-compatible-chat.md), [internal model-client document](internal/llm.md), and owning package tests. |
| Internal package implementation | The [architecture policy](policy/architecture.md), [internal component overview](internal/overview.md), and focused internal document listed for that package. |
| Tests or test fixtures | The [testing policy](policy/testing.md), owning package, and focused internal document listed by the component overview. |
| Maintained example | The [example](../examples/go-library/prepare/main.go), [consumer guide](consumers/pkg-promptkit.md), [framework format reference](formats.md), and [documentation policy](policy/documentation.md). |
| Documentation | The [documentation policy](policy/documentation.md) and canonical owner of every affected contract. |
| Release preparation or publication | The [release procedure](release.md). |
For cross-cutting changes, follow every applicable row. Do not create
@@ -50,8 +53,10 @@ validation from the Promptkit repository root:
```sh
go test ./...
go test -race ./...
go vet ./...
go build ./...
go run ./examples/go-library/prepare
```
Check formatting across every tracked Go file:
@@ -75,7 +80,7 @@ behavior checked by the module.
## Focused Validation
Use focused checks while iterating, then run the complete validation sequence
before accepting the change. The root package currently supports:
before accepting the change. The root package supports:
```sh
go test .
@@ -83,17 +88,16 @@ go vet .
go build .
```
Filter tests by name without assuming a future package layout:
Filter tests by name without assuming a fixed internal package layout:
```sh
go test ./... -run 'TestName'
```
Replace `TestName` with a useful regular expression. When internal packages are
introduced, target only paths that actually exist, such as
`go test ./path/to/package`, and consult the internal component overview for
their owning documentation. A filtered or package-specific run does not replace
the complete repository validation.
Replace `TestName` with a useful regular expression. Target only paths that
exist, and consult the internal component overview for their owning
documentation. A filtered or package-specific run does not replace the
complete repository validation.
## Coordinated Work With Scriptorium

276
docs/formats.md Normal file
View File

@@ -0,0 +1,276 @@
# Framework Format Reference
## Purpose
This document is the canonical contract for Promptkit prompt-definition,
profile, and schema files. The [Go package consumer guide](consumers/pkg-promptkit.md)
explains how to select these sources and invoke the engine. The
[OpenAI-compatible integration contract](integrations/openai-compatible-chat.md)
owns the resulting outbound wire behavior.
Prompt and profile sources recursively discover files ending in `.yaml` or
`.yml`. YAML decoding is strict: unknown fields are errors for the selected
definition. Definitions are selected by their YAML `id`, not their file name
or directory.
## Prompt Definitions
A prompt definition describes inputs, Go-template messages, an optional
default profile, and an output contract.
```yaml
id: meeting.summary
version: "1.0.0"
default_profile: local-summary
description: Summarize a synthetic meeting note.
session_id: '{{.session}}'
inputs:
- name: note
required: true
content_type: text/plain
description: Meeting note to summarize.
messages:
- role: system
content: Return a concise summary.
cache_control:
type: ephemeral
ttl: 1h
- role: user
content_file: ./summary.user.md
output:
format: markdown
validation_mode: basic
repair_attempts: 0
```
| Field | Required | Meaning |
| --- | --- | --- |
| `id` | yes | Non-empty prompt identifier used by `RunRequest.PromptID`. |
| `version` | yes | Non-empty version selected by an optional `RunRequest.PromptVersion`. |
| `default_profile` | no | Non-empty profile ID used when the request omits `ProfileID`. |
| `description` | no | Human-readable description. |
| `session_id` | no | Go template rendered from request variables and input helpers. |
| `inputs` | no | Declared input metadata. |
| `messages` | yes | One or more chat-message templates. |
| `output` | yes | Output format and validation settings. |
When a request omits a version, the selected prompt ID must identify exactly
one definition. When it supplies a version, the ID and version pair must be
unique.
### Inputs
Each `inputs` item has these fields:
| Field | Required | Meaning |
| --- | --- | --- |
| `name` | yes | Non-empty name used by the request input map and `input` template helper. Names must be unique. |
| `required` | no | When true, preparation fails if the request omits the input. The default is false. |
| `content_type` | no | Expected media-type metadata. |
| `description` | no | Human-readable input description. |
Requests supply inputs as inline or file-backed `ArtifactRef` values. Declared
required inputs must be present. A template reference also requires the named
input to exist, whether or not it was declared. Extra request inputs are
allowed.
### Messages And Templates
Each message has a non-empty `role` and exactly one of:
- `content`, containing an inline Go template; or
- `content_file`, naming a file whose contents are the Go template.
For directory and `fs.FS` prompt sources, `content_file` resolves relative to
the prompt file and remains within the source root. `WithPromptFile` also
resolves it relative to that file.
Request variables are the template data, so a variable named `audience` is
referenced as `{{.audience}}`. The `{{input "note"}}` helper renders the body
of a named input. Missing variables and input references are errors.
The optional `session_id` uses the same template data and input helper. Its
rendered value is trimmed, omitted when empty, and limited to 256 Unicode code
points.
### Cache Control
`cache_control` is optional and has these fields:
| Field | Required | Values |
| --- | --- | --- |
| `type` | yes | `ephemeral` |
| `ttl` | no | Empty or `1h` |
Promptkit preserves cache-control metadata on the rendered message. The
outbound integration determines its wire representation.
### Output Contract
| Field | Required | Values or behavior |
| --- | --- | --- |
| `format` | yes | `text`, `markdown`, or `json`. |
| `validation_mode` | yes | `none`, `basic`, `json`, or `json_schema`. |
| `schema_path` | for `json_schema` | Path to a schema in the configured schema source. |
| `repair_attempts` | no | Integer zero or greater; omitted means zero. |
The validation modes behave as follows:
- `none` skips content validation;
- `basic` requires non-empty generated content;
- `json` requires valid JSON; and
- `json_schema` requires valid JSON that satisfies the selected schema.
`format` controls output artifact metadata. JSON Schema mode also supplies the
schema to compatible model clients as structured-output metadata. The public
engine does not install an output repairer, so its validation is single-pass
even when a positive `repair_attempts` value is present.
A request-level `OutputContract` replaces the complete prompt output contract.
It does not merge individual fields. If its format is empty, Promptkit uses
`text`.
## Profile Definitions
A profile supplies model execution settings:
```yaml
id: local-summary
endpoint: http://localhost:8000/v1
model: example-model
temperature: 0.2
max_tokens: 500
top_p: 0.95
timeout_seconds: 90
service_tier: flex
reasoning_effort: medium
api_key_env: EXAMPLE_API_KEY
extra_params:
provider_option: enabled
```
| Field | Required | Meaning |
| --- | --- | --- |
| `id` | yes | Non-empty profile identifier. IDs must be unique within one source. |
| `endpoint` | yes | Non-empty OpenAI-compatible base URL, including an API version path when required. |
| `model` | yes | Non-empty provider model name. |
| `temperature` | no | Number from 0 through 2. |
| `max_tokens` | no | Integer zero or greater. |
| `top_p` | no | Number from 0 through 1. |
| `timeout_seconds` | no | Per-generation deadline in whole seconds; integer zero or greater. |
| `service_tier` | no | Provider-specific request tier. |
| `reasoning_effort` | no | Provider-specific reasoning setting. |
| `api_key_env` | no | Name of an environment variable containing the API key. |
| `extra_params` | no | JSON-compatible provider-specific outbound fields. |
Raw `api_key` is prohibited in profile YAML. Store only an environment
variable name in `api_key_env`.
`extra_params` accepts null, booleans, finite numbers, strings, arrays, and
objects with string keys. Keys must be non-empty. With the built-in client,
they also cannot collide with the standard fields listed in the
[outbound request contract](integrations/openai-compatible-chat.md#request-body).
### Defaults And Overrides
Execution settings resolve in this order:
1. framework defaults;
2. the selected profile; and
3. request `ExecutionTargetOverride` values.
The framework defaults are:
| Setting | Default |
| --- | --- |
| `temperature` | `0` |
| `max_tokens` | `0` |
| `top_p` | `1` |
| `timeout_seconds` | `600` |
Numeric zero in a file or in-memory profile means that the profile does not
replace the framework default. Numeric request overrides use pointers, so an
explicit zero is preserved. In particular, an explicit request
`timeout_seconds` of zero disables the per-generation deadline while leaving
the caller context and transport timeout intact.
Non-empty request strings replace profile strings. A non-empty request
`ExtraParams` map replaces the profile map rather than merging keys.
The [outbound integration contract](integrations/openai-compatible-chat.md)
defines how the effective settings are serialized.
### Source And Profile Precedence
An explicit request profile ID takes precedence over the prompt's
`default_profile`. If neither is present, preparation fails.
Profile sources resolve matching IDs in this order:
1. in-memory profiles supplied with `WithProfiles`;
2. a profile file, `fs.FS`, or configured profile directory; and
3. embedded built-in profiles.
A higher-precedence source falls back only when the profile is absent. An
invalid matching profile is an error and does not fall back. In-memory
`Profile` values follow the same ranges as YAML profiles. They use
`APIKeyRequired` for request-scoped credentials instead of `api_key_env`.
## Built-In Profile Catalog
Built-ins use the OpenRouter-compatible endpoint and
`OPENROUTER_API_KEY`. A custom or in-memory profile with the same ID takes
precedence.
| Provider | ID | Model |
| --- | --- | --- |
| aion-labs | `aion-2` | `aion-labs/aion-2.0` |
| anthropic | `claude-fable-latest` | `~anthropic/claude-fable-latest` |
| anthropic | `claude-haiku-latest` | `~anthropic/claude-haiku-latest` |
| anthropic | `claude-opus-latest` | `~anthropic/claude-opus-latest` |
| anthropic | `claude-sonnet-latest` | `~anthropic/claude-sonnet-latest` |
| deepseek | `deepseek-3-2` | `deepseek/deepseek-v3.2` |
| deepseek | `deepseek-4-flash` | `deepseek/deepseek-v4-flash` |
| deepseek | `deepseek-4-pro` | `deepseek/deepseek-v4-pro` |
| google | `gemini-2-flash` | `google/gemini-2.5-flash` |
| google | `gemini-2-flash-lite` | `google/gemini-2.5-flash-lite` |
| google | `gemini-2-pro` | `google/gemini-2.5-pro` |
| google | `gemini-3-flash-lite` | `google/gemini-3.1-flash-lite` |
| google | `gemini-flash-latest` | `~google/gemini-flash-latest` |
| google | `gemini-pro-latest` | `~google/gemini-pro-latest` |
| google | `gemma-4-31b` | `google/gemma-4-31b-it:exacto` |
| minimax | `minimax-m2` | `minimax/minimax-m2.5` |
| minimax | `minimax-m3` | `minimax/minimax-m3` |
| mistral | `mistral-large-2512` | `mistralai/mistral-large-2512` |
| mistral | `mistral-medium-3-5` | `mistralai/mistral-medium-3-5` |
| mistral | `mistral-small-3` | `mistralai/mistral-small-3.2-24b-instruct` |
| mistral | `mistral-small-4` | `mistralai/mistral-small-2603` |
| nvidia | `nemotron-3-ultra` | `nvidia/nemotron-3-ultra-550b-a55b` |
| openai | `gpt-5-mini` | `openai/gpt-5.4-mini` |
| openai | `gpt-5-nano` | `openai/gpt-5.4-nano` |
## Schemas
Schemas are JSON documents selected by a prompt or request
`schema_path`. For a directory or `fs.FS` source, paths resolve within the
configured source root. Referenced nested schemas resolve relative to the
owning schema document. `WithSchemaFile` exposes one schema, addressed by its
base name.
An unreadable, invalid, or unresolvable schema produces an operational
validation error. Generated content that is valid JSON but does not satisfy the
schema produces a failed validation result.
## Credentials
Credential values belong at the request or environment boundary, never in
prompt, profile, schema, or example files:
- a file profile names an environment variable with `api_key_env`;
- an in-memory profile may set `APIKeyRequired`;
- a request can provide a direct `APIKey` or override `APIKeyEnv`; and
- a direct request key takes precedence over environment lookup.
Promptkit validates required credential availability during preparation.
Direct keys are excluded from JSON results and redacted by public string
formatters. Environment-variable names may appear in prepared metadata, but
their values do not.

View File

@@ -6,7 +6,9 @@ This document defines the outbound HTTP behavior implemented by Promptkit's
internal OpenAI-compatible model client. The
[internal model-client document](../internal/llm.md) owns implementation flow,
errors, and test ownership. The root Promptkit engine uses this client by
default unless a consumer injects another implementation.
default unless a consumer injects another implementation. The
[framework format reference](../formats.md) owns the profile and prompt values
that produce these outbound settings.
## Endpoint And Method

View File

@@ -6,7 +6,9 @@ This document describes Promptkit's internal model-client implementation. The
[architecture policy](../policy/architecture.md) owns the library boundary,
and the
[OpenAI-compatible chat integration](../integrations/openai-compatible-chat.md)
owns the observable outbound HTTP contract.
owns the observable outbound HTTP contract. The
[framework format reference](../formats.md) owns the profile and prompt
settings consumed by the client.
The concrete client remains under `internal/llm`. The root engine assembles it
as the default implementation behind Promptkit's public client boundary.

View File

@@ -12,15 +12,16 @@ contributor workflow and validation.
| Component | Implemented responsibility | References |
| --- | --- | --- |
| Root `promptkit` package | Provides the supported engine facade, source and injection options, public request and result values, built-in profile construction, extension interfaces, value conversion, redacted formatting, and public error mapping. | [Package GoDoc](../../doc.go), [engine assembly](../../engine.go) |
| `examples/go-library/prepare` | Demonstrates an offline downstream consumer using a prompt file, in-memory profile, inline input, and `Prepare`. It is not a public library package. | [Example program](../../examples/go-library/prepare/main.go) |
| `internal/domain` | Defines internal framework values for requests, artifacts, prompt definitions, profiles, execution targets, rendering, generation, and validation. | [Domain declarations](../../internal/domain/domain.go) |
| `internal/defaults` | Defines application-neutral framework constants and constructs the default execution target. It contains no CLI, server, or inbound HTTP limits. | [Framework defaults](../../internal/defaults/defaults.go) |
| `internal/filecatalog` | Provides deterministic YAML discovery and path helpers for operating-system filesystems and `fs.FS` sources. | [File catalog](../../internal/filecatalog/catalog.go) |
| `internal/promptdef` | Loads strictly decoded, validated prompt definitions from filesystem and `fs.FS` sources, including version selection and contained file-backed message content. | [Prompt-definition repository](../../internal/promptdef/filesystem_repository.go) |
| `internal/profile` | Loads strictly decoded, validated execution profiles from filesystem and `fs.FS` sources and composes repositories with error-preserving fallback. | [Profile repositories](../../internal/profile/filesystem_repository.go) |
| `internal/profile/builtin` | Embeds the built-in execution profile catalog and combines it with an optional primary repository. | [Built-in profile repository](../../internal/profile/builtin/repository.go) |
| `internal/promptdef` | Loads strictly decoded, validated prompt definitions from filesystem and `fs.FS` sources, including version selection and contained file-backed message content. | [Framework formats](../formats.md), [prompt-definition repository](../../internal/promptdef/filesystem_repository.go) |
| `internal/profile` | Loads strictly decoded, validated execution profiles from filesystem and `fs.FS` sources and composes repositories with error-preserving fallback. | [Framework formats](../formats.md), [profile repositories](../../internal/profile/filesystem_repository.go) |
| `internal/profile/builtin` | Embeds the built-in execution profile catalog and combines it with an optional primary repository. | [Built-in catalog](../formats.md#built-in-profile-catalog), [repository](../../internal/profile/builtin/repository.go) |
| `internal/prompt` | Renders prompt messages from Go templates with artifact, variable, session, and cache-control data. | [Go-template renderer](../../internal/prompt/go_renderer.go) |
| `internal/artifact` | Resolves ordinary inline and unrestricted caller-selected file references into copied artifacts with metadata and hashes. | [Internal sources and validation](sources.md) |
| `internal/validate` | Validates basic, JSON, and JSON Schema output using operating-system filesystem or `fs.FS` schema sources. | [Internal sources and validation](sources.md) |
| `internal/validate` | Validates basic, JSON, and JSON Schema output using operating-system filesystem or `fs.FS` schema sources. | [Framework formats](../formats.md#schemas), [internal sources and validation](sources.md) |
| `internal/llm` | Defines the internal generation boundary and implements outbound OpenAI-compatible chat requests, response decoding, authentication, and deadline handling. | [Internal model client](llm.md) |
| `internal/usecase` | Coordinates preparation and execution across internal sources, rendering, artifact loading, generation, validation, and optional repair. | [Internal runner](runner.md) |
@@ -29,7 +30,7 @@ representations. Consumers depend only on the root facade.
## Maintenance
Update this inventory as framework extraction introduces packages or changes
component responsibilities. List only implemented components; proposed package
Update this inventory as implementation adds packages or changes component
responsibilities. List only implemented components; proposed package
boundaries belong in temporary planning documents until their implementation
lands.

View File

@@ -11,6 +11,8 @@ categories.
The runner remains under `internal/usecase` and is assembled by the root
Promptkit engine. Its concrete type is not part of the public API.
The [framework format reference](../formats.md) owns prompt, profile, schema,
and override semantics consumed by the runner.
## Collaborators

View File

@@ -7,13 +7,14 @@ rendering, and output-validation behavior. The
[architecture policy](../policy/architecture.md) owns the library boundary and
dependency rules. None of these internal packages is a supported consumer API,
and the root engine assembles them behind its public source options and values.
The [framework format reference](../formats.md) owns the exact file fields,
validation modes, built-in catalog, and source precedence.
## Prompt Definitions
`internal/promptdef` loads prompt definitions from an operating-system
filesystem or an `fs.FS`. It discovers YAML deterministically, decodes fields
strictly, validates definitions, selects an ID and optional version, and
resolves file-backed message content within the selected source.
`internal/promptdef` discovers YAML deterministically, decodes and validates
definitions, selects an ID and optional version, and resolves file-backed
message content within the selected operating-system or `fs.FS` source.
Its package tests own prompt selection, strict decoding, definition validation,
duplicate detection, and source containment:
@@ -21,10 +22,9 @@ duplicate detection, and source containment:
## Profiles And Built-Ins
`internal/profile` loads strictly decoded execution profiles from an
operating-system filesystem or an `fs.FS`. It validates required profile data,
rejects raw API keys, and supports a primary repository with fallback only
when the primary reports that a profile is absent.
`internal/profile` loads and validates execution profiles from an
operating-system filesystem or an `fs.FS`. It supports a primary repository
with fallback only when the primary reports that a profile is absent.
`internal/profile/builtin` embeds the maintained built-in profile catalog and
can place a caller-selected repository ahead of that catalog. Profile behavior
@@ -57,10 +57,9 @@ control into the rendered prompt. The
## Schemas And Output Validation
`internal/validate` provides validators backed by an operating-system
filesystem or an `fs.FS`. Validation can be skipped, require non-empty output,
require JSON, or apply a JSON Schema loaded with the source's path semantics.
Invalid generated content is returned as a validation result; inability to
load, register, or compile a schema is an operational error.
filesystem or an `fs.FS`. Invalid generated content is returned as a validation
result; inability to load, register, or compile a schema is an operational
error.
The [validator tests](../../internal/validate/standard_validator_test.go) own
basic, JSON, JSON Schema, source resolution, schema loading, compilation, and

View File

@@ -9,8 +9,9 @@ implemented packages without redefining these rules.
## System Shape
Promptkit is an importable Go library. It does not provide a runnable command,
an HTTP service, or another application process.
Promptkit is an importable Go library. It does not ship a command, an HTTP
service, or another application process. Repository examples demonstrate
library use but are not Promptkit applications or release artifacts.
The module root contains package `promptkit`, which is the public facade. It
provides the supported engine, configuration and source options, requests,
@@ -40,6 +41,10 @@ The implemented internal components consist of:
- `internal/usecase`, which coordinates preparation and execution across the
internal framework components.
The `examples/go-library/prepare` package is a maintained downstream consumer
of the root facade. It does not expose a library package or participate in
internal assembly.
The root facade assembles the internal repositories, renderer, validator,
outbound client, and use-case runner while translating public values and
errors at the library boundary. The defaults and renderer depend on the domain

View File

@@ -75,13 +75,14 @@ mechanisms, not secret values.
| Testing policy | `docs/policy/testing.md` | Test philosophy, risk-based sufficiency, test boundaries, doubles, coverage guidance, regression policy, and test maintenance. | Subsystem behavior, exact public contracts, subsystem-specific test inventories, and implementation plans. |
| Release procedure | `docs/release.md`, when present | Required release validation, version and tag procedure, release ordering, and post-publication checks. | General contributor workflow, public API semantics, and decision history. |
| Exact exported Go API | Go declarations and GoDoc, as APIs are implemented | Exported names, signatures, types, values, errors, and exact behavioral contracts. | Task-oriented consumer walkthroughs, implementation details, and future API proposals. |
| Framework file formats | `docs/formats.md` | Prompt-definition and profile YAML fields, schema references, defaults, validation modes, built-in profiles, credentials, and file-to-request precedence. | Exported Go declarations, outbound wire behavior, internal parsing mechanics, and application configuration. |
| Consumer guidance | `docs/consumers/`, when consumer workflows require dedicated guidance | Task-oriented use of implemented public APIs, minimal examples, and consumer responsibilities. | Exact exported declarations and internal mechanics. |
| Durable integration contracts | `docs/integrations/`, when integrations exist | External formats and protocols, compatibility behavior, and upstream or downstream responsibilities. | Internal transformations and public Go declarations. |
| Implemented component inventory | `docs/internal/overview.md` | Current packages and components, their implemented responsibilities, and links to focused internal documents. | Normative architecture, contributor workflow, external contracts, and proposed components. |
| Internal subsystem behavior | Other files under `docs/internal/`, when a subsystem needs durable detail | Implementation flow, internal collaborators and state transitions, package-local guarantees and failures, and relevant tests. | Global architecture invariants, public API definitions, and future package plans. |
| Architectural decision history | `docs/adr/`, when repository-local decisions require records | Significant decisions, context, alternatives, rationale, consequences, and supersession history. | Current behavior reference, implementation status, and task sequencing. |
| Temporary feature roadmaps | `docs/roadmap/`, while planned work needs coordination | Proposed or accepted scope, sequencing, gates, and implementation status. | Implemented behavior reference and durable decision rationale. |
| Complete copyable artifacts | `examples/`, when maintained examples exist | Valid inputs, Go programs, and other files intended to be copied or run. | Field-by-field reference, exact API declarations, and prose explanation. |
| Complete copyable artifacts | `examples/` | Valid inputs, Go programs, and other files intended to be copied or run. | Field-by-field reference, exact API declarations, and prose explanation. |
Conditional owners do not require placeholder files or directories. Create a
consumer, integration, subsystem, ADR, roadmap, or example document only when
@@ -105,6 +106,9 @@ for a task. Internal documents explain how Promptkit implements them. Internal
documentation may identify a public type or external format as a dependency,
but must link to its canonical definition rather than restate it.
The [framework format reference](../formats.md) owns exact prompt, profile, and
schema-file contracts. Integration documents own external wire formats.
### Security Topics
This policy owns what documentation and examples may contain. Architecture owns

View File

@@ -55,6 +55,15 @@ documentation-link, and repository-hygiene checks before accepting changes.
Introducing hosted CI later would supplement, not silently redefine, this
documented validation model.
The complete test sequence includes ordinary and race-enabled package tests.
The maintained offline consumer workflow is also run from the repository root:
```sh
go test ./...
go test -race ./...
go run ./examples/go-library/prepare
```
Tests in the default suite must be deterministic, offline, and independent of
real credentials. They must not invoke paid APIs, use live network
dependencies, or depend on mutable external services. Tests that require live
@@ -77,6 +86,10 @@ Use each test type where it protects a distinct risk:
relied upon by consumers.
- Integration tests use real collaborators when correctness depends on their
interaction, while replacing live or nondeterministic external boundaries.
- External-package root tests exercise the public facade as a Go consumer,
while internal package tests own focused implementation behavior.
- The maintained offline preparation example protects one representative
assembled consumer workflow without contacting a model provider.
- Fixtures should be minimal, synthetic, versioned with the behavior they
exercise, and free of credentials or private data.
- Golden files are appropriate only when the complete output is intentionally
@@ -154,7 +167,8 @@ A test failing is not the same as a test needing to be edited. Many tests may co
Configurable thresholds and defaults must not be duplicated throughout the test suite.
For example, do not encode an internal concurrency limit indirectly:
The following fragments are illustrative rather than standalone Go programs.
Do not encode an internal concurrency limit indirectly:
```go
// Production policy:

View File

@@ -47,8 +47,10 @@ Run the same default Go validation required by the
```sh
go test ./...
go test -race ./...
go vet ./...
go build ./...
go run ./examples/go-library/prepare
```
Check every tracked Go file and repository whitespace:

View File

@@ -0,0 +1,60 @@
package main
import (
"context"
"encoding/json"
"fmt"
"os"
"gitea.maximumdirect.net/eric/promptkit"
)
type summary struct {
PromptID string `json:"prompt_id"`
PromptVersion string `json:"prompt_version"`
SelectedProfile string `json:"selected_profile"`
Model string `json:"model"`
MessageCount int `json:"message_count"`
}
func main() {
engine, err := promptkit.NewEngine(
promptkit.Config{},
promptkit.WithPromptFile("examples/go-library/prepare/prompt.yaml"),
promptkit.WithProfiles(promptkit.Profile{
ID: "offline-example",
Endpoint: "https://example.invalid/v1",
Model: "offline-model",
}),
)
if err != nil {
exit(err)
}
prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{
PromptID: "example.prepare",
Inputs: map[string]promptkit.ArtifactRef{
"note": promptkit.Inline("Ada finished the migration review."),
},
})
if err != nil {
exit(err)
}
encoder := json.NewEncoder(os.Stdout)
encoder.SetIndent("", " ")
if err := encoder.Encode(summary{
PromptID: prepared.PromptID,
PromptVersion: prepared.PromptVersion,
SelectedProfile: prepared.SelectedProfileID,
Model: prepared.EffectiveModelParams.Model,
MessageCount: len(prepared.Messages),
}); err != nil {
exit(err)
}
}
func exit(err error) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}

View File

@@ -0,0 +1,16 @@
id: example.prepare
version: "1.0.0"
default_profile: offline-example
description: Prepare a prompt without contacting a model provider.
inputs:
- name: note
required: true
content_type: text/plain
messages:
- role: system
content: Summarize the note in one sentence.
- role: user
content: '{{input "note"}}'
output:
format: text
validation_mode: basic