Skip to contents

Tempest brings STORM and Co-STORM research workflows to R. It combines multi-perspective research, source and claim tracking, cited writing, selected or generated experts, scientific reports, and resumable research state.

This article helps you choose a workflow and produce a first result. Provider-backed examples are not executed while the vignette is built, so rendering the article makes no model or search calls and requires no provider credentials.

Choose a workflow

Start with the interface that matches the outcome you need:

Goal Interface Result
Create an evidence-backed report tempest_run() A report, sources, claims, outline, and run state
Explore a topic interactively tempest_app() or tempest_session() A continuing Co-STORM conversation, mind map, evidence, and report

Most package users should begin with scripted STORM. Co-STORM is useful when the research question should evolve through dialogue. Tempest 0.2 has no application-neutral workflow or runtime API.

Install and load Tempest

Install the development package from GitHub:

# install.packages("pak")
pak::pak("JamesHWade/tempest")

Then load it:

Tempest uses ellmer for model access. Configure the credential required by your chosen provider outside your R source files. For the default OpenAI models, Tempest uses ellmer::chat_openai(): with released ellmer that means OPENAI_API_KEY; with the ellmer subscription-authentication port (chat_openai(auth = )) Tempest passes auth = "codex" and reuses the file-backed ChatGPT subscription managed by Codex CLI (if Codex has not stored file-backed credentials, run codex login -c 'cli_auth_credentials_store="file"'). Do not put credentials in a Tempest configuration, expert profile, workflow specification, or saved run.

tempest_config() controls model roles, retrieval, evidence policy, caching, and Co-STORM behavior. A single model string can be used for every role, or models can be a named list for finer control.

This small first-run configuration uses Wikipedia search, which does not need a separate search-provider key:

cfg <- tempest_config(
  models = "openai/gpt-5.6-luna",
  search_provider = "wikipedia",
  max_search_results = 4,
  max_sources = 12,
  citation_policy = "source_attributed"
)

The default "native" search provider uses provider-native web search when available and falls back to Wikipedia. Other providers may require their own environment variables.

Create a first STORM report

tempest_run() performs five stages:

  1. discover perspectives and expert profiles;
  2. research questions from each perspective;
  3. draft and refine an outline;
  4. write cited sections; and
  5. polish and publish the Markdown report.

Start with two experts and a small question budget while learning the package:

result <- tempest_run(
  "What are the main technical and policy barriers to recycling grid-scale batteries?",
  config = cfg,
  n_experts = 2,
  max_questions_per_perspective = 2,
  output_dir = "tempest-runs",
  run_id = "grid-battery-recycling",
  verbose = TRUE
)

This call uses the configured model and search provider, so it incurs provider usage and requires network access. output_dir creates a run directory and persists each stage after it completes.

The returned list contains the main report and the state used to create it:

cat(tempest_report(result))

result$title
result$perspectives
result$experts
result$outline

sources <- tempest_sources(result)
claims <- tempest_claims(result)
supports <- tempest_claim_supports(result)

utils::head(sources[c("id", "title", "url")])
utils::head(claims[
  c(
    "claim_id",
    "claim_text",
    "source_ids",
    "verification_status",
    "support_score"
  )
])
utils::head(supports)

The research workspace holds run-scoped provisional evidence. Retrieved resources, proposed claims, exact claim-by-evidence-span support records, and citations remain inspectable instead of being flattened into report text. The pair records are authoritative; claim summaries and citation-audit tables are derived projections. The authoritative product report is read with tempest_report(result).

tempest_report() is the one read accessor for both product shapes. It returns the exact committed bytes and never generates, repairs, or republishes a report. For Co-STORM, generate and commit with session$publish(), then read those exact bytes with tempest_report(session).

Every STORM and Co-STORM publication runs the exact verifier ProgramSet stage and atomically binds claim-by-evidence-span support. citation_policy controls only report rendering and unsupported-claim handling:

  • "source_attributed" converts known inline source IDs to footnotes without disabling product verification;
  • "claim_verified" exposes threshold-verified support in the rendered report and final references; and
  • "strict" fails publication unless each publishable assertion is bound to a completed, provenance-bound verification result at the configured threshold and cites that claim’s exact source set.

Use min_support_score in tempest_config() to set the verification threshold. Under the "strict" policy, on_unsupported_claim controls whether weak claims are flagged, dropped, revised, or retained with an explicit warning. They are never presented as unmarked verified facts.

Review promotion to Graft

A succeeded product can become a deterministic proposal for Graft review without granting Tempest acceptance authority:

bundle <- tempest_promotion_bundle(result)
trusted_bundle_id <- bundle@bundle_id
tempest_save_promotion_bundle(bundle, "promotion/grid-battery-recycling")
bundle <- tempest_read_promotion_bundle(
  "promotion/grid-battery-recycling",
  expected_bundle_id = trusted_bundle_id
)

store <- graft::graft_store("research-artifacts", create = TRUE)
selection <- tempest_publish_artifact_research(result, store)
# Host review and acceptance remain explicit; saving alone does not approve.
accepted <- graft::graft_accept(
  store, graft::graft_read_selection(store, selection), "research",
  expected = NULL, key = "review-1",
  actor = "reviewer", reason = "Reviewed", purpose = "research"
)

Tempest does not commit during bundle construction or planning. The current closed promotion format contains exact Sources, Claims, EvidenceSpans, ClaimSupports, and extraction and verification ProgramArtifacts. A closed proof projection retains the exact resources, claims, spans, and supports needed to recompute every retained StageRecord digest. A selection must include every output bound by each retained extraction or verification record; Tempest rejects partial stage-output selection instead of packaging nonselected evidence. Reading requires the original bundle id as an out-of-band trust pin; bundle-local checksums establish internal consistency, not authenticity. Older bundle shapes are rejected. Research promotion never mints a GovernedProcedure; stored research does not authorize program execution.

The constructor accepts only a completed tempest_run() result or a succeeded, quiescent TempestSession. Independently supplied Workspace, Manifest, and StageRecord values cannot prove the exact completed product or its committed report.

Review the completed trajectory

Build a bounded, reconstructable review without creating new product or Graft authority:

review <- tempest_trajectory_review(result)
proposed_review <- tempest_trajectory_review(
  result,
  promotion_bundle = bundle
)
artifact_store <- graft::graft_store("research-artifacts", create = TRUE)
selection <- tempest_publish_artifact_research(result, artifact_store)
accepted <- graft::graft_accept(
  artifact_store, graft::graft_read_selection(artifact_store, selection),
  "research", expected = NULL, key = "review-1",
  actor = "reviewer", reason = "Reviewed the evidence", purpose = "briefing"
)
accepted_review <- tempest_trajectory_review(
  result, store = artifact_store, selection = selection,
  stream = "research", decision = accepted@id
)

The closed ten-field projection contains the product identity, ordered StageRecord summaries, safe terminal Deputy identities, fixed ProgramSet references, input and optional promotion knowledge, evidence identities, explicit joins, and structural findings. Variable lanes retain at most 250 records while binding the complete lane count and digest. It contains no prompts, responses, source content, local paths, credentials, live objects, or capabilities, and Tempest does not persist it.

Join proofs distinguish authority-validated bindings and exact identity from mere correlation. A correlation_id appears only in correlated_with joins with correlation_only proof and never establishes causation or authorship. Mutable progress events remain outside the review identity. Proposed and historically accepted states bind the exact completed product and publication. An old acceptance remains inspectable after withdrawal; current reuse still requires fresh admission. Cross-product publications fail closed. Schema 2 directly replaces the earlier receipt-based review contract.

Input reported_decision metadata is explicitly unverified host provenance. Malformed metadata is omitted from the review; only the output acceptance is verified against the selected store event.

Resume a staged run

When output_dir is supplied, Tempest saves completed stages, source and claim records, report artifacts, and checksummed metadata beneath the run directory. Resume with the same topic, configuration, output directory, and run ID:

result <- tempest_run(
  "What are the main technical and policy barriers to recycling grid-scale batteries?",
  config = cfg,
  n_experts = 2,
  max_questions_per_perspective = 2,
  output_dir = "tempest-runs",
  run_id = "grid-battery-recycling",
  resume = TRUE,
  verbose = TRUE
)

Completed stages are loaded rather than rerun. Keep model, retrieval, and workflow settings stable when continuing an existing run.

Current readers accept only ResearchWorkspace snapshot schema 7, Co-STORM snapshot and bundle schema 13, STORM bundle schema 10 with state schema 5, ProgramSet schema 2, research-manifest schema 5, StageRecord output-digest payload schema 3, and promotion-bundle schema 1. Every other version is rejected, as is any missing or extra field or value that becomes valid only after coercion. Shared envelope primitives, ResearchWorkspace snapshots, Co-STORM bundles, and STORM bundles have separate product owners; no generic run-persistence reader or compatibility layer remains.

Every typed attempt is saved with its exact stage, program, evaluator, trace, support decision, and fallback path. Structured output is validated as a whole before product state changes. A resumed running attempt is recorded as cancelled, and the final report adds a deterministic Execution review for failed, cancelled, policy-fallback, or nonverified grounded outcomes.

Supply your own expert team

By default, STORM generates a topic-specific expert pool and pairs it with the discovered perspectives. A host can instead choose exact profiles from its own expert pool:

experts <- list(
  tempest_expert(
    name = "Recycling Engineer",
    title = "Battery recovery specialist",
    description = "Focuses on process yield, safety, and scale-up.",
    instructions = "Separate demonstrated performance from projections.",
    focus_areas = c("hydrometallurgy", "process safety"),
    initial_questions = "Which recovery steps constrain full-scale yield?"
  ),
  tempest_expert(
    name = "Policy Analyst",
    title = "Circular-economy policy specialist",
    description = "Focuses on incentives, standards, and accountability.",
    instructions = "Compare jurisdictions and preserve policy uncertainty.",
    focus_areas = c("producer responsibility", "recycling standards"),
    initial_questions = "Which policies have changed recovery outcomes?"
  )
)

result <- tempest_run(
  "What are the main technical and policy barriers to recycling grid-scale batteries?",
  config = cfg,
  experts = experts,
  output_dir = "tempest-runs",
  run_id = "selected-expert-recycling",
  verbose = TRUE
)

Generated and supplied experts use the same canonical constructor. Profiles are immutable descriptions of scientific perspectives, and Tempest derives each profile’s expert_id and version from its six authored fields. Keep live tools, clients, credentials, and roster state outside the serialized profile. Product code attaches only the tools required for its STORM or Co-STORM role, and Co-STORM retirement remains manager-owned session-roster state rather than profile data.

Explore interactively with Co-STORM

Launch the bundled Shiny application for a multi-expert conversation, live mind map, evidence tables, and report generation. The app uses optional packages from Suggests; install them if they are not already available:

pak::pak(
  c(
    "shiny",
    "bslib",
    "shinychat",
    "DT",
    "visNetwork",
    "promises",
    "later",
    "mirai",
    "zip"
  )
)

tempest_app()

For console control, create a session directly:

session <- tempest_session(
  "Grid-scale battery recycling",
  config = cfg,
  n_experts = 3
)

session$warmup(verbose = TRUE)
answer <- session$step(
  "Which barriers are most likely to constrain deployment this decade?"
)
cat(answer$answer)

session$publish(
  style = "executive",
  include_references = TRUE
)
committed_report <- tempest_report(session)
cat(committed_report)

tempest_session_save(
  session,
  "tempest-runs/grid-battery-session",
  overwrite = TRUE
)

restored <- tempest_session_resume(
  "tempest-runs/grid-battery-session",
  config = cfg
)

Each expert keeps its own conversation continuity and receives only the role-specific tools needed for that session. The moderator delegates by stable expert ID, and evidence collected during dialogue remains available to the final report. Session bundles preserve durable research state, but not credentials, live chat handles, tools, or authenticated clients. Configure fresh supported chats and retrieval dependencies through config before resuming.

Snapshot, save, restore, and resume accept only the exact schema-13 Co-STORM product. Expert, transcript, mind-map, StageRecord, Workspace, report, suggested-question, and artifact selection state must pass integrity checks.

The moderator and experts use persistent Deputy agents as the required Co-STORM runtime. Tempest disables ambient file, shell, R, and package-install capabilities, then allowlists only the tools already attached for that role. Web authority is limited to that frozen surface, including an explicit provider-native search tool when configured. Each product-owned session ID is passed to the Deputy Agent constructor and checked against the live runtime before any run. Snapshots persist canonical opaque terminal traces for each run and never serialize the Deputy Agent or provider credentials. Those execution identities support correlation and audit joins only; they do not claim that an execution caused, authored, or validated report content.

The bundled app includes Chat, STORM, Mind Map, Sources, Facts, Transcript, Report, and Run review panels. The Run review shows the bounded authoritative StageRecord trajectory beside separately labeled, untrusted live progress. Co-STORM persistence is explicit bounded archive download and upload; there is no browser-temporary autosave. The STORM panel has no parallel perspective control and runs through the maintained asynchronous worker path. Progress, persistence, and successful publication use polite live status; validation, cancellation, and publication failures use alerts.

A host app can embed that same asynchronous STORM adapter without calling The Shiny modules are Tempest implementation details. The bundled application is reachable only through tempest_app(); there is no supported contract for embedding its panels in a host app.

Product boundary

Tempest supports only tempest_run() and tempest_session() as research product entry points, with tempest_app() for the bundled application. A completed run is read through tempest_report(), tempest_sources(), tempest_claims(), tempest_claim_supports(), and tempest_trajectory_review(); the retriever, mutable workspace, manifest, and stage state are not part of that surface. No compatibility layer is provided.

Where to go next

Start with a narrow topic, a small expert and question budget, and durable output. Expand model roles, retrieval, parallelism, and evaluation only after the first workflow behaves as intended.