# Workflow.Current (which run is this code in?)

> `Workflow.Current` is the workflow run this code is executing in — one value saying its id, the workflow's declared name, the state whose body is running, the id of the row the run tracks, and the run that started it from its own body. It answers in a workflow's body and in everything that body calls; anywhere else it is null. A kit that records what was done for a process — an agent's receipt, the cost of a model call — reads it to say which run the work belongs to, with nothing written at the call.

<!-- id: workflow-run-facts · area: workflow · stability: preview · html: https://osysharp.com/reference/workflow/run-facts/ -->

## Summary        {#summary}
A function called from a workflow's body often needs to say **which run** it worked for — to write that on a row it
keeps, or to charge what it spent there. It reads it:

```osy syntax
var run = Workflow.Current;               // WorkflowRunInfo? — null when this code is in no run
if (run != null) {
  note.Run = run.Id;                      // the run's own id
  note.Workflow = run.Workflow;           // "Onboarding" — the workflow's declared name
  note.State = run.State;                 // "Vetting" — the state whose body is running
  note.About = run.Item;                  // the id of the row the run tracks
}
note.Run = Workflow.Current?.Id;          // …or one fact, null outside a run
```

## Signature      {#signature}
```osy syntax
Workflow.Current -> WorkflowRunInfo?      // the run this code is in; null outside one

public sealed class WorkflowRunInfo {     // a core class: always in scope, no `using`
  public Guid   Id;                       // the run
  public string Workflow;                 // the workflow's declared name
  public string State;                    // the state whose body is running, by name
  public Guid?  Item;                     // the id of the row the run tracks (`this.Item.Id`)
  public Guid?  Starter;                  // the run whose body started this one; null for a run nothing started from a body
}
```

## Description    {#description}

### Where does it answer?   {#where}
Wherever [`Workflow.InRun`](https://osysharp.com/reference/workflow/in-run/) is true: in a workflow's `enter`, `exit`, `on`, `Start` and reminder
bodies, and in every function, method and lambda those call, to any depth. A page's action, a function called over
the API, an `[On]` handler and a test's own body are in no run: `Workflow.Current` is null there.

### What is it for?   {#for}
For code that works **for** a run without being part of its workflow — a kit, usually. The workflow's own body has
`this.Item` and knows its own name; a function three calls down has neither, and must not be handed them as
arguments by every caller in between.

- `Osysharp.Llm` charges every model call made in a run to the run's workflow and to the run itself, so what a
  process cost is counted as it happens ([Model spend — budgets, the meter and the price book (Llm kit)](https://osysharp.com/reference/agent/llm-spend/)).
- `Osysharp.Agents` writes the run on the receipt of a piece of work given in one, so the work is found from the run
  and the run from the work ([Agents in business processes — an agent's work as a step of a workflow, told on the run (Agents.Processes kit)](https://osysharp.com/reference/agent/processes/)).
- `Osysharp.Processes` keeps each line a process says about itself (`Processes.Note(…)`) with the state it was
  said in ([Processes — every run of a business process, listed and read from start to now (Processes kit)](https://osysharp.com/reference/workflow/processes-kit/)).

### What is `Item`, and what may be done with it?   {#item}
The id of the row the run tracks — what the body itself calls `this.Item.Id`. It says **which** row, and nothing of
what is in it: reading that row is an ordinary read, under the row's own security, by whoever is reading.

### What is `Starter`?   {#starter}
The run whose body started this one — by `await Workflow.Run("step", child)`, as a parallel leg, or as a saga's
undo. It is null for a run that autostarted or that `Workflow.Run(entity)` started from outside any body. Walking
it upward finds the run at the top of a tree of runs.

### Is it the same for the whole of a run?   {#same}
Yes. Inside one run every read answers the same id, workflow, item and starter — also after the run was parked for a
week and resumed — and `State` is the state whose body is running. So it is read where it is needed, twice in one
body if it helps; there is nothing to keep and nothing to name. Each read answers a value of its own, which is yours
to hold: it does not change under you, and changing it changes nothing.

A run that was started under an older version of the app answers with the names that version declared.

## Examples       {#examples}
```osy title="a function says which run it is in; a run it awaited says which run started it" run app=workflow-run-facts
app Letters {
  use Osysharp.Workflow;
  model "model/**/*.osy";
}

using Osysharp.Workflow;

enum LetterStatus { Drafting, Checking, Sent }
enum CheckStatus  { Asked, Passed }

entity Letter {
  LetterStatus Status;
  /// What the body says of its own run, state by state.
  [MaxLength(400)] string Seen = "";
  Guid? Run;
  /// The row the run says it tracks.
  Guid? Tracked;
  security { allow read, create, update when IsAuthenticated || IsAnonymous; }
}

entity Check {
  CheckStatus Status = CheckStatus.Asked;
  [MaxLength(200)] string Seen = "";
  Guid? Run;
  Guid? StartedBy;
  security { allow read, create, update when IsAuthenticated || IsAnonymous; }
}

/// ⭐ Which run is this code in? A plain function: it answers for whichever body called it.
string WhereAmI() {
  var run = Workflow.Current;
  return run == null ? "in no run" : run.Workflow + " at " + run.State;
}

workflow CheckFlow {
  Tracks = Check.Status; Autostart = false; Initial = Asked;
  state Asked {
    enter {
      this.Item.Seen = WhereAmI();
      this.Item.Run = Workflow.Current?.Id;
      this.Item.StartedBy = Workflow.Current?.Starter;  // the run whose body started this one
      goto Passed;
    }
  }
  terminal success Passed { }
}

workflow LetterFlow {
  Tracks = Letter.Status; Autostart = true; Initial = Drafting;
  state Drafting {
    enter {
      this.Item.Run = Workflow.Current?.Id;
      this.Item.Tracked = Workflow.Current?.Item;       // this.Item's own id — for code that has no `this.Item`
      this.Item.Seen = WhereAmI();
      goto Checking;
    }
  }
  state Checking {
    enter {
      var check = Workflow.Once("check", () => new Check { });
      await Workflow.Run("check", check);
      this.Item.Seen = this.Item.Seen + ", " + WhereAmI();
      goto Sent;
    }
  }
  terminal success Sent { }
}

[Test]
void outside_a_run_there_is_none() {
  Assert.Null(Workflow.Current);
  Assert.Null(Workflow.Current?.Id);
  Assert.Equal("in no run", WhereAmI());
}

[Test]
void a_body_and_everything_it_calls_know_their_run() {
  var letter = new Letter { };
  Workflow.Settle(letter);
  Assert.Equal(LetterStatus.Sent, letter.Status);
  Assert.Equal("LetterFlow at Drafting, LetterFlow at Checking", letter.Seen);
  // The run it awaited is another run: its own id, its own workflow — and it knows which run started it.
  var check = Check.Single();
  Assert.Equal("CheckFlow at Asked", check.Seen);
  Assert.NotNull(letter.Run);
  Assert.Equal(letter.Id, letter.Tracked);
  Assert.True(check.Run != letter.Run);
  Assert.Equal(letter.Run, check.StartedBy);
}

[Test]
void the_value_is_the_callers_to_keep() {
  var letter = new Letter { };
  Workflow.Settle(letter);
  // What a body read is a plain value: it was stored on the row, and says the same long after the run has ended.
  Assert.Equal(letter.Id, Letter.Single().Tracked);
  Assert.Null(Workflow.Current);                        // …and the test's own body is still in no run
}
```

## Notes          {#notes}
- They say where the code is running, not who is running it — that is [actor — who just did this](https://osysharp.com/reference/workflow/actor/).
- The run's rows are the engine's own, and an app cannot read them ([For(entity).Audit](https://osysharp.com/reference/workflow/audit/) is how an app reads what
  happened to a run, by the row it tracks). `Workflow.Current` is what a run says of itself.
- A function reached from an `[On]` handler is in no run, even when the event was raised in one: record the run
  where the event is raised, and carry it on the event or on the row it is about.

## See also       {#see-also}
- [Workflow.InRun (can this code wait?)](https://osysharp.com/reference/workflow/in-run/) — is this code in a run at all, and may it wait?
- [Workflow.Run (start a workflow)](https://osysharp.com/reference/workflow/run/) — starting a run, and waiting for one
- [Agents in business processes — an agent's work as a step of a workflow, told on the run (Agents.Processes kit)](https://osysharp.com/reference/agent/processes/) — an agent's work as a step of a process
- [Processes — every run of a business process, listed and read from start to now (Processes kit)](https://osysharp.com/reference/workflow/processes-kit/) — every run of a process, listed and read
