Logo ProcessCore

Creating A Dataset

This walkthrough builds a small process graph from F# objects. The goal is to show the model shape rather than every field in the specification.

Dataset

Start with a dataset. Administrative metadata is optional, but an identifier is the stable handle for the dataset.

let dataset = Dataset("demo-dataset") // or ARC("demo-dataset") for an ARC package

let lab = Organization("Core Lab")
let curator = Agent("Ada", familyName = "Lovelace", email = "ada@example.org", affiliation = lab)
let citation = ScholarlyArticle("Minimal ProcessCore example", authors = [ curator ])

dataset.Title <- Some "Minimal ProcessCore example"
dataset.Description <- Some "One extraction process with nested quality control."
dataset.License <- Some "CC-BY-4.0"
dataset.DatePublished <- Some "2026-07-03"
dataset.DateCreated <- Some "2026-07-03"
dataset.DateModified <- Some "2026-07-03"
dataset.AddAgent(curator)
dataset.AddCitation(citation)

The administrative metadata is attached to the package itself rather than the individual processes.

Recipe

A protocol describes the method. Formal parameters define expected knobs, for which values should be provided when the protocol is executed.

let protocol = Recipe()
let temperature = FormalParameter("temperature")
protocol.Name <- Some "Extraction"
protocol.IntendedUse <- Some (DefinedTerm("sample extraction"))
protocol.AddParameter(temperature)

Components are non-transformed entities in a protocol, such as machines or reagents.

let centrifuge = Annotation(name = "centrifuge", value = "Eppendorf 5420")
let buffer = Annotation(name = "buffer", value = "PBS")

protocol.AddComponent(centrifuge)
protocol.AddComponent(buffer)

Process

Processes are the core of the process graph. They are concrete executions of a protocol, with specific parameter values, and input and output entities.

First, we define input and output, i.e. Sample or Data nodes.

let leaf = Sample("Leaf tissue")

let extractData = Data("raw/extract.csv")
extractData.EncodingFormat <- Some "text/csv"

A Process connects those inputs to outputs. We also attach parameter values to the process, which should correspond to the protocol's formal parameters.

let extraction = Process("Extraction")
let degrees25 = Annotation(name = "temperature", value = "25", unit = "degree Celsius", instanceOf = temperature)
extraction.ExecutesRecipe <- Some protocol
extraction.SetInputSample(leaf)
extraction.SetOutputData(extractData)
extraction.AddParameterValue(degrees25)

dataset.AddProcess(extraction)

Nested Datasets

Datasets can contain child datasets. When a child dataset is added, its process nodes are re-canonicalized against the root dataset.

let child = Dataset("qc-dataset")
child.Title <- Some "Quality control"

let qcReport = Data("qc/extract-report.tsv")

let qc = Process("Quality Control")
qc.SetInputData(extractData)
qc.SetOutputData(qcReport)
let threshold = FormalParameter("threshold")
let threshold95 = Annotation(name = "threshold", value = "0.95", instanceOf = threshold)
qc.AddParameterValue(threshold95)

child.AddProcess(qc)
dataset.AddPart(child)

The parent process output and the child process input are the same logical Data node: same path, no selector. After AddPart, they are also the same object instance in the root dataset.

let qcInputAfterAttach =
    match qc.Input.Value with
    | DataNode d -> d
    | SampleNode _ -> failwith "Expected data input"

let sharedDataIdentity =
    obj.ReferenceEquals(extractData, qcInputAfterAttach)

sharedDataIdentity
true

The graph is now queryable from either the dataset or any node.

let finalNodes =
    dataset.FinalNodes()
    |> Seq.map (fun n -> n.Key())
    |> Seq.toList

finalNodes
["D:qc/extract-report.tsv"]

What To Use When

Task

API

Create a container

Dataset(identifier) or ARC(identifier)

Add package metadata

dataset.Title, dataset.Description, dataset.License, dataset.DatePublished, dataset.AddAgent, dataset.AddCitation

Add a process

dataset.AddProcess(process)

Add nested datasets

dataset.AddPart(child)

Connect samples or files

process.SetInputSample, process.SetOutputData

Attach process parameters

process.AddParameterValue

Attach characteristics/factors

node.AddAdditionalProperty

Attach protocol components

protocol.AddComponent

namespace ProcessCore
val mermaidBlock: text: string -> string
val text: string
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
System.String.Trim() : string
System.String.Trim( trimChars: char array) : string
System.String.Trim(trimChar: char) : string
namespace System
namespace System.Net
type WebUtility = static member HtmlDecode: value: string -> string + 1 overload static member HtmlEncode: value: string -> string + 1 overload static member UrlDecode: encodedValue: string -> string static member UrlDecodeToBytes: encodedValue: byte array * offset: int * count: int -> byte array static member UrlEncode: value: string -> string static member UrlEncodeToBytes: value: byte array * offset: int * count: int -> byte array
<summary>Provides methods for encoding and decoding URLs when processing Web requests.</summary>
System.Net.WebUtility.HtmlEncode(value: string) : string
System.Net.WebUtility.HtmlEncode(value: string, output: System.IO.TextWriter) : unit
val sprintf: format: Printf.StringFormat<'T> -> 'T
val dataset: Dataset
Multiple items
type Dataset = inherit DynamicObj new: identifier: string * ?title: string * ?description: string * ?additionalType: string * ?license: string * ?datePublished: string * ?dateCreated: string * ?dateModified: string * ?processes: Process seq * ?hasPart: Dataset seq * ?dataFiles: Data seq * ?agents: Agent seq * ?citations: ScholarlyArticle seq * ?dataContexts: DataContext seq * ?additionalProperty: Annotation seq -> Dataset member AddAdditionalProperty: pv: Annotation -> unit member AddAgent: agent: Agent -> unit member AddCitation: article: ScholarlyArticle -> unit member AddDataContext: dataContext: DataContext -> unit member AddDataFile: data: Data -> unit member AddPart: child: Dataset -> unit member AddProcess: proc: Process -> unit member AllAgents: unit -> ResizeArray<Agent> ...
<summary> Container and context for data, processes, administrative metadata, and datamap entries. schema.org/Dataset </summary>

--------------------
new: identifier: string * ?title: string * ?description: string * ?additionalType: string * ?license: string * ?datePublished: string * ?dateCreated: string * ?dateModified: string * ?processes: Process seq * ?hasPart: Dataset seq * ?dataFiles: Data seq * ?agents: Agent seq * ?citations: ScholarlyArticle seq * ?dataContexts: DataContext seq * ?additionalProperty: Annotation seq -> Dataset
val lab: Organization
Multiple items
type Organization = inherit DynamicObj new: name: string * ?id: string * ?url: string -> Organization override Equals: obj: obj -> bool override GetHashCode: unit -> int member Id: string option with get, set member Name: string with get, set member Url: string option with get, set
<summary> Entity representing an organization involved in creating, curating, or hosting a dataset. schema.org/Organization </summary>

--------------------
new: name: string * ?id: string * ?url: string -> Organization
val curator: Agent
Multiple items
type Agent = inherit DynamicObj new: givenName: string * ?id: string * ?familyName: string * ?email: string * ?affiliation: Organization * ?identifier: string * ?jobTitles: DefinedTerm seq * ?additionalName: string * ?address: string * ?telephone: string * ?additionalProperty: Annotation seq -> Agent member AddAdditionalProperty: pv: Annotation -> unit member AddJobTitle: jobTitle: DefinedTerm -> unit override Equals: obj: obj -> bool override GetHashCode: unit -> int member RemoveAdditionalProperty: pv: Annotation -> unit member RemoveJobTitle: jobTitle: DefinedTerm -> unit member AdditionalName: string option with get, set member AdditionalProperty: ResizeArray<Annotation> ...
<summary> Individual contributor or contact associated with a dataset or article. schema.org/Agent </summary>

--------------------
new: givenName: string * ?id: string * ?familyName: string * ?email: string * ?affiliation: Organization * ?identifier: string * ?jobTitles: DefinedTerm seq * ?additionalName: string * ?address: string * ?telephone: string * ?additionalProperty: Annotation seq -> Agent
val citation: ScholarlyArticle
Multiple items
type ScholarlyArticle = inherit DynamicObj new: headline: string * ?id: string * ?identifier: string * ?creativeWorkStatus: DefinedTerm * ?authors: Agent seq * ?additionalProperty: Annotation seq -> ScholarlyArticle member AddAdditionalProperty: pv: Annotation -> unit member AddAuthor: agent: Agent -> unit override Equals: obj: obj -> bool override GetHashCode: unit -> int member RemoveAdditionalProperty: pv: Annotation -> unit member RemoveAuthor: agent: Agent -> unit member AdditionalProperty: ResizeArray<Annotation> member Authors: ResizeArray<Agent> ...
<summary> Scholarly publication associated with a dataset. schema.org/ScholarlyArticle </summary>

--------------------
new: headline: string * ?id: string * ?identifier: string * ?creativeWorkStatus: DefinedTerm * ?authors: Agent seq * ?additionalProperty: Annotation seq -> ScholarlyArticle
property Dataset.Title: string option with get, set
union case Option.Some: Value: 'T -> Option<'T>
property Dataset.Description: string option with get, set
property Dataset.License: string option with get, set
property Dataset.DatePublished: string option with get, set
property Dataset.DateCreated: string option with get, set
property Dataset.DateModified: string option with get, set
member Dataset.AddAgent: agent: Agent -> unit
member Dataset.AddCitation: article: ScholarlyArticle -> unit
val protocol: Recipe
Multiple items
type Recipe = inherit DynamicObj new: ?name: string * ?description: string * ?version: string * ?url: string * ?intendedUse: DefinedTerm * ?additionalType: string * ?parameters: FormalParameter seq * ?components: Annotation seq * ?additionalProperty: Annotation seq -> Recipe member AddAdditionalProperty: pv: Annotation -> unit member AddComponent: pv: Annotation -> unit member AddParameter: fp: FormalParameter -> unit override Equals: obj: obj -> bool override GetHashCode: unit -> int member RemoveAdditionalProperty: pv: Annotation -> unit member RemoveComponent: pv: Annotation -> unit member RemoveParameter: fp: FormalParameter -> unit ...
<summary> Description of a planned procedure. bioschemas.org/LabProtocol </summary>

--------------------
new: ?name: string * ?description: string * ?version: string * ?url: string * ?intendedUse: DefinedTerm * ?additionalType: string * ?parameters: FormalParameter seq * ?components: Annotation seq * ?additionalProperty: Annotation seq -> Recipe
val temperature: FormalParameter
Multiple items
type FormalParameter = inherit DynamicObj new: name: string * ?nameTAN: string * ?defaultValue: DefinedTerm -> FormalParameter override Equals: obj: obj -> bool override GetHashCode: unit -> int member DefaultValue: DefinedTerm option with get, set member Name: string with get, set member NameTAN: string option with get, set
<summary> Describes the shape and type of a protocol parameter slot. bioschemas.org/FormalParameter </summary>

--------------------
new: name: string * ?nameTAN: string * ?defaultValue: DefinedTerm -> FormalParameter
property Recipe.Name: string option with get, set
property Recipe.IntendedUse: DefinedTerm option with get, set
Multiple items
type DefinedTerm = inherit DynamicObj new: name: string * ?tan: string * ?inDefinedTermSet: string -> DefinedTerm override Equals: obj: obj -> bool override GetHashCode: unit -> int member SemanticallyEquals: other: DefinedTerm -> bool member TermAccessionShort: unit -> string member TryGetTSR: unit -> string option member InDefinedTermSet: string option with get, set member Name: string with get, set member TAN: string option with get, set
<summary> Ontology annotation referencing a term in a controlled vocabulary or ontology. schema.org/DefinedTerm </summary>

--------------------
new: name: string * ?tan: string * ?inDefinedTermSet: string -> DefinedTerm
member Recipe.AddParameter: fp: FormalParameter -> unit
val centrifuge: Annotation
Multiple items
type Annotation = inherit DynamicObj new: name: string * ?value: string * ?unit: string * ?nameTAN: string * ?valueTAN: string * ?unitTAN: string * ?additionalType: string * ?instanceOf: FormalParameter -> Annotation override Equals: obj: obj -> bool override GetHashCode: unit -> int member NameEquals: term: DefinedTerm -> bool member AdditionalType: string option with get, set member InstanceOf: FormalParameter option with get, set member Name: string with get, set member NameTAN: string option with get, set member NameText: string ...
<summary> Extensible key-value-unit triple. Primary extension mechanism of ProcessCore. schema.org/PropertyValue </summary>

--------------------
new: name: string * ?value: string * ?unit: string * ?nameTAN: string * ?valueTAN: string * ?unitTAN: string * ?additionalType: string * ?instanceOf: FormalParameter -> Annotation
val buffer: Annotation
member Recipe.AddComponent: pv: Annotation -> unit
val leaf: Sample
Multiple items
type Sample = inherit DynamicObj new: name: string * ?additionalType: string * ?additionalProperty: Annotation seq -> Sample member AddAdditionalProperty: pv: Annotation -> unit member AllAnnotations: ?scope: ResizeArray<Process> -> ResizeArray<Annotation> member AllConnectedNodes: ?scope: ResizeArray<Process> -> ResizeArray<IONode> member AllConnectedProcesses: ?scope: ResizeArray<Process> -> ResizeArray<Process> member ConnectedData: ?scope: ResizeArray<Process> -> ResizeArray<Data> member ConnectedSamples: ?scope: ResizeArray<Process> -> ResizeArray<Sample> member DownstreamAnnotations: ?recipeName: string * ?scope: ResizeArray<Process> -> ResizeArray<Annotation> member DownstreamData: ?scope: ResizeArray<Process> -> ResizeArray<Data> ...
<summary> Input or output biological, chemical, or digital sample in the process graph. bioschemas.org/Sample </summary>

--------------------
new: name: string * ?additionalType: string * ?additionalProperty: Annotation seq -> Sample
val extractData: Data
Multiple items
namespace Microsoft.FSharp.Data

--------------------
type Data = inherit DynamicObj new: path: string * ?selector: string * ?selectorFormat: string * ?encodingFormat: string * ?additionalType: string * ?hasPart: Data seq * ?additionalProperty: Annotation seq -> Data member AddAdditionalProperty: pv: Annotation -> unit member AddPart: data: Data -> unit member AllAnnotations: ?scope: ResizeArray<Process> -> ResizeArray<Annotation> member AllConnectedNodes: ?scope: ResizeArray<Process> -> ResizeArray<IONode> member AllConnectedProcesses: ?scope: ResizeArray<Process> -> ResizeArray<Process> member ConnectedData: ?scope: ResizeArray<Process> -> ResizeArray<Data> member ConnectedSamples: ?scope: ResizeArray<Process> -> ResizeArray<Sample> member DownstreamAnnotations: ?recipeName: string * ?scope: ResizeArray<Process> -> ResizeArray<Annotation> ...
<summary> Data file or selected fragment produced or consumed by processes. schema.org/MediaObject or File </summary>

--------------------
new: path: string * ?selector: string * ?selectorFormat: string * ?encodingFormat: string * ?additionalType: string * ?hasPart: Data seq * ?additionalProperty: Annotation seq -> Data
property Data.EncodingFormat: string option with get, set
<summary> MIME type </summary>
val extraction: Process
Multiple items
type Process = inherit DynamicObj new: name: string * ?executesRecipe: Recipe * ?additionalType: string * ?input: IONode * ?output: IONode * ?parameterValue: Annotation seq -> Process member AddParameterValue: pv: Annotation -> unit member AnnotationsByName: name: string -> ResizeArray<Annotation> member CanonicalizeAllNodes: ds: Dataset -> unit member ClearInput: unit -> unit member ClearOutput: unit -> unit override Equals: obj: obj -> bool override GetHashCode: unit -> int member GetParameterValue: name: string -> Annotation ...
<summary> Core transformation node. Connects inputs to outputs by executing a recipe. bioschemas.org/LabProcess </summary>

--------------------
new: name: string * ?executesRecipe: Recipe * ?additionalType: string * ?input: IONode * ?output: IONode * ?parameterValue: Annotation seq -> Process
val degrees25: Annotation
type unit = Unit
property Process.ExecutesRecipe: Recipe option with get, set
member Process.SetInputSample: m: Sample -> unit
member Process.SetOutputData: d: Data -> unit
member Process.AddParameterValue: pv: Annotation -> unit
member Dataset.AddProcess: proc: Process -> unit
val child: Dataset
val qcReport: Data
val qc: Process
member Process.SetInputData: d: Data -> unit
val threshold: FormalParameter
val threshold95: Annotation
member Dataset.AddPart: child: Dataset -> unit
val qcInputAfterAttach: Data
property Process.Input: IONode option with get
property Option.Value: IONode with get
union case IONode.DataNode: Data -> IONode
val d: Data
union case IONode.SampleNode: Sample -> IONode
val failwith: message: string -> 'T
val sharedDataIdentity: bool
type obj = System.Object
System.Object.ReferenceEquals(objA: obj, objB: obj) : bool
val finalNodes: string list
member Dataset.FinalNodes: unit -> ResizeArray<IONode>
module Seq from Microsoft.FSharp.Collections
val map: mapping: ('T -> 'U) -> source: 'T seq -> 'U seq
val n: IONode
member IONode.Key: unit -> string
val toList: source: 'T seq -> 'T list

Type something to start searching.