Source profileQuality 93/100Review permissions

synthetic-sciences/openscience/backend/cli/skills/cloud-compute/tinker/SKILL.md

tinker-fine-tuning

Provides guidance for fine-tuning LLMs using the Tinker cloud training API from Thinking Machines Lab. Use when running supervised fine-tuning, reinforcement learning (GRPO/PPO), or LoRA training on cloud GPUs via Tinker's managed infrastructure instead of local compute.

Source repository stars
3,338
Declared platforms
0
Static risk flags
1
Last source update
2026-08-26
Source checked
2026-08-26

Decision brief

What it does: where it fits

Expert guidance for fine-tuning large language models using Tinker's managed cloud training API. Tinker handles GPU allocation, model hosting, and distributed training — you write the training logic, Tinker runs it on cloud infrastructure.

Best for

  • Fine-tune models up to 235B parameters without managing GPU infrastructure
  • Run LoRA training on Qwen, Llama, DeepSeek, or GPT-OSS models
  • Train vision-language models (Qwen3-VL)

Not for

  • Tasks that require unconfirmed production actions or broad system permissions.
  • Environments where the pinned source and install steps cannot be inspected.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/synthetic-sciences/openscience --skill "backend/cli/skills/cloud-compute/tinker"
Safe inspection promptEditorial

Inspect the Agent Skill "tinker-fine-tuning" from https://github.com/synthetic-sciences/openscience/blob/95be136c06386eb18546ce94d134d2c7e66976ac/backend/cli/skills/cloud-compute/tinker/SKILL.md at commit 95be136c06386eb18546ce94d134d2c7e66976ac. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

Workflow

What the source asks the agent to do

  1. 01

    Workflow 1: Supervised Fine-Tuning (Cookbook)

    Use this for standard SFT with JSONL or HuggingFace datasets.

    [ ] Prepare data in JSONL chat format ({"messages": [...]})[ ] Choose base model (see model table below)[ ] Set hyperparameters (LR, batch size, epochs)
  2. 02

    Implementation

    python import json import chz import asyncio from tinkercookbook.supervised import train from tinkercookbook.supervised.types import ChatDatasetBuilderCommonConfig from tinkercookbook.supervised.data import FromConversationFileBuilder from tinkercookbook.renderers import TrainOn…

    python import json import chz import asyncio from tinkercookbook.supervised import train from tinkercookbook.supervised.types import ChatDatasetBuilderCommonConfig from tinkercookbook.supervised.data import FromConversa…modelname = "Qwen/Qwen3-30B-A3B" renderername = getrecommendedrenderername(modelname) numepochs = 3 datafile = "trainingdata.jsonl"commonconfig = ChatDatasetBuilderCommonConfig( modelnamefortokenizer=modelname, renderername=renderername, maxlength=2048, batchsize=128, trainonwhat=TrainOnWhat.ALLASSISTANTMESSAGES, )
  3. 03

    --- Exact usage reporting (auto-captured by CLI) ---

    tokenizer = gettokenizer(modelname) totaltokens = 0 with open(datafile) as f: for line in f: row = json.loads(line) text = " ".join(m.get("content", "") for m in row.get("messages", [])) totaltokens += len(tokenizer.encode(text)) totaltokens = numepochs print(f'\n[OPENSCIENCEUSA…

    tokenizer = gettokenizer(modelname) totaltokens = 0 with open(datafile) as f: for line in f: row = json.loads(line) text = " ".join(m.get("content", "") for m in row.get("messages", [])) totaltokens += len(tokenizer.enc…modelname = "meta-llama/Llama-3.1-8B" renderername = modelinfo.getrecommendedrenderername(modelname) batchsize = 128 groupsize = 16 maxtokens = 256builder = Gsm8kDatasetBuilder( batchsize=batchsize, groupsize=groupsize, renderername=renderername, modelnamefortokenizer=modelname, )
  4. 04

    Workflow 2: Reinforcement Learning (GRPO-style)

    Use this for training with reward functions — math reasoning, format compliance, verifiable tasks.

    [ ] Define reward function(s) that return float scores[ ] Choose group size (16 recommended)[ ] Set up sampling → reward → training loop
  5. 05

    Implementation (Cookbook)

    python import json import asyncio import chz from tinkercookbook.rl import train from tinkercookbook.recipes.mathrl.mathenv import Gsm8kDatasetBuilder from tinkercookbook import modelinfo

    python import json import asyncio import chz from tinkercookbook.rl import train from tinkercookbook.recipes.mathrl.mathenv import Gsm8kDatasetBuilder from tinkercookbook import modelinfomodelname = "meta-llama/Llama-3.1-8B" renderername = modelinfo.getrecommendedrenderername(modelname) batchsize = 128 groupsize = 16 maxtokens = 256builder = Gsm8kDatasetBuilder( batchsize=batchsize, groupsize=groupsize, renderername=renderername, modelnamefortokenizer=modelname, )

Permission review

Static risk signals and limitations

Runs scripts

medium · line 333

The documentation asks the agent to run terminal commands or scripts.

python -m tinker_cookbook.recipes.preference.train \

Runs scripts

medium · line 368

The documentation asks the agent to run terminal commands or scripts.

python -m tinker_cookbook.eval.run_inspect_evals \

Evidence record

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score93/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars3,338SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
synthetic-sciences/openscience
Skill path
backend/cli/skills/cloud-compute/tinker/SKILL.md
Commit
95be136c06386eb18546ce94d134d2c7e66976ac
License
Apache-2.0
Collected
2026-08-26
Default branch
main
View the original SKILL.md

Tinker API - Cloud LLM Fine-Tuning

Expert guidance for fine-tuning large language models using Tinker's managed cloud training API. Tinker handles GPU allocation, model hosting, and distributed training — you write the training logic, Tinker runs it on cloud infrastructure.

When to Use This Skill

Use Tinker when you need to:

  • Fine-tune models up to 235B parameters without managing GPU infrastructure
  • Run LoRA training on Qwen, Llama, DeepSeek, or GPT-OSS models
  • Train vision-language models (Qwen3-VL)
  • Implement custom RL loops (GRPO, PPO, importance sampling) on cloud GPUs
  • Iterate quickly with a training API that handles hardware provisioning

Do NOT use Tinker when:

  • You need full fine-tuning (not LoRA) — Tinker only supports LoRA
  • You need to train custom architectures — Tinker supports specific model families
  • You want to use your own GPUs — use Axolotl, Unsloth, or LLaMA-Factory instead
  • You need offline/air-gapped training

Tinker vs Alternatives:

NeedUse
Managed cloud LoRA trainingTinker
Local GPU fine-tuningAxolotl, Unsloth, LLaMA-Factory
Full parameter fine-tuningDeepSpeed + Transformers
RLHF with TRL locallyTRL + GRPO skill
Quantized trainingUnsloth, bitsandbytes

Quick Reference

TopicReference
Setup & Core ConceptsGetting Started
API Classes & TypesAPI Reference
Supervised LearningSupervised Learning
RL Training & EnvironmentsReinforcement Learning
DPO, RLHF & DistillationDPO & Preference Learning
Loss FunctionsLoss Functions
Chat TemplatesRendering
Models & LoRAModels & LoRA
EvaluationsEvaluations
Example ScriptsRecipes

Installation

pip install tinker tinker-cookbook
# TINKER_API_KEY must be set — connect Tinker in the OpenScience dashboard to sync your API key.
# Verify: [ -n "$TINKER_API_KEY" ] && echo "set" || echo "not set"

Workflow 1: Supervised Fine-Tuning (Cookbook)

Use this for standard SFT with JSONL or HuggingFace datasets.

Checklist

  • Prepare data in JSONL chat format ({"messages": [...]})
  • Choose base model (see model table below)
  • Set hyperparameters (LR, batch size, epochs)
  • Run training via Cookbook
  • Monitor metrics (train_mean_nll, test/nll)
  • Save and deploy weights

Implementation

import json
import chz
import asyncio
from tinker_cookbook.supervised import train
from tinker_cookbook.supervised.types import ChatDatasetBuilderCommonConfig
from tinker_cookbook.supervised.data import FromConversationFileBuilder
from tinker_cookbook.renderers import TrainOnWhat
from tinker_cookbook.model_info import get_recommended_renderer_name
from tinker_cookbook.hyperparam_utils import get_lr
from tinker_cookbook.tokenizer_utils import get_tokenizer

model_name = "Qwen/Qwen3-30B-A3B"
renderer_name = get_recommended_renderer_name(model_name)
num_epochs = 3
data_file = "training_data.jsonl"

common_config = ChatDatasetBuilderCommonConfig(
    model_name_for_tokenizer=model_name,
    renderer_name=renderer_name,
    max_length=2048,
    batch_size=128,
    train_on_what=TrainOnWhat.ALL_ASSISTANT_MESSAGES,
)

dataset_builder = FromConversationFileBuilder(
    common_config=common_config,
    file_path=data_file,
)

blueprint = chz.Blueprint(train.Config).apply({
    "log_path": "/tmp/sft-run",
    "model_name": model_name,
    "dataset_builder": dataset_builder,
    "learning_rate": get_lr(model_name),
    "lr_schedule": "linear",
    "num_epochs": num_epochs,
    "lora_rank": 32,
})

config = blueprint.make()
asyncio.run(train.main(config))

# --- Exact usage reporting (auto-captured by CLI) ---
tokenizer = get_tokenizer(model_name)
total_tokens = 0
with open(data_file) as f:
    for line in f:
        row = json.loads(line)
        text = " ".join(m.get("content", "") for m in row.get("messages", []))
        total_tokens += len(tokenizer.encode(text))
total_tokens *= num_epochs
print(f'\n[OPENSCIENCE_USAGE] {json.dumps({"service": "tinker", "event_type": "training", "model": model_name, "tokens_used": total_tokens})}')

Data Format

JSONL with chat messages (one per line):

{"messages": [{"role": "user", "content": "Translate to French: hello"}, {"role": "assistant", "content": "bonjour"}]}

TrainOnWhat Options

OptionWhen to Use
ALL_ASSISTANT_MESSAGESStandard SFT, multi-turn conversations
LAST_ASSISTANT_MESSAGEClassification, chain-of-thought where only final answer matters

Workflow 2: Reinforcement Learning (GRPO-style)

Use this for training with reward functions — math reasoning, format compliance, verifiable tasks.

Checklist

  • Define reward function(s) that return float scores
  • Choose group size (16 recommended)
  • Set up sampling → reward → training loop
  • Monitor correct, format, reward/total, KL divergence
  • Keep KL below 0.01 for stable training

Implementation (Cookbook)

import json
import asyncio
import chz
from tinker_cookbook.rl import train
from tinker_cookbook.recipes.math_rl.math_env import Gsm8kDatasetBuilder
from tinker_cookbook import model_info

model_name = "meta-llama/Llama-3.1-8B"
renderer_name = model_info.get_recommended_renderer_name(model_name)
batch_size = 128
group_size = 16
max_tokens = 256

builder = Gsm8kDatasetBuilder(
    batch_size=batch_size,
    group_size=group_size,
    renderer_name=renderer_name,
    model_name_for_tokenizer=model_name,
)

blueprint = chz.Blueprint(train.Config).apply({
    "model_name": model_name,
    "log_path": "/tmp/rl-run",
    "dataset_builder": builder,
    "learning_rate": 4e-5,
    "max_tokens": max_tokens,
})

config = blueprint.make()
asyncio.run(train.main(config))

# --- Exact usage reporting (auto-captured by CLI) ---
# For RL: estimate from batch_size × group_size × max_tokens × num_batches
# The exact count comes from the training loop — check /tmp/rl-run for logs
import glob, os
log_files = sorted(glob.glob("/tmp/rl-run/metrics*.json"))
total_tokens = 0
for lf in log_files:
    with open(lf) as f:
        for line in f:
            m = json.loads(line)
            total_tokens += m.get("num_tokens", 0)
if total_tokens == 0:
    # Fallback estimate: batch_size × group_size × max_tokens × num_batches
    total_tokens = batch_size * group_size * max_tokens * 100
print(f'\n[OPENSCIENCE_USAGE] {json.dumps({"service": "tinker", "event_type": "training", "model": model_name, "tokens_used": total_tokens})}')

Custom RL with Low-Level API

For full control over sampling, reward computation, and advantage centering:

import json
import tinker
from tinker import types
from tinker.types.tensor_data import TensorData
import torch

model_name = "meta-llama/Llama-3.1-8B"
service_client = tinker.ServiceClient()
training_client = service_client.create_lora_training_client(
    base_model=model_name, rank=32
)

total_tokens = 0  # Track exact tokens for billing

for batch_idx, batch_rows in enumerate(dataset):
    path = training_client.save_weights_for_sampler(name=f"{batch_idx:06d}").result().path
    sampling_client = service_client.create_sampling_client(model_path=path)

    datums = []
    for question, answer in batch_rows:
        prompt = renderer.build_generation_prompt([{"role": "user", "content": question}])
        prompt_tokens = prompt.to_ints()
        result = sampling_client.sample(
            prompt=prompt, num_samples=16,
            sampling_params=types.SamplingParams(max_tokens=256, stop=renderer.get_stop_sequences()),
        ).result()

        rewards = [compute_reward(seq, answer) for seq in result.sequences]
        mean_reward = sum(rewards) / len(rewards)
        advantages = [r - mean_reward for r in rewards]
        if all(a == 0 for a in advantages):
            continue

        for seq, advantage in zip(result.sequences, advantages):
            tokens = prompt_tokens + seq.tokens
            ob_len = len(prompt_tokens) - 1
            datum = types.Datum(
                model_input=types.ModelInput.from_ints(tokens=tokens[:-1]),
                loss_fn_inputs={
                    "target_tokens": TensorData.from_torch(torch.tensor(tokens[1:])),
                    "logprobs": TensorData.from_torch(torch.tensor([0.0]*ob_len + list(seq.logprobs))),
                    "advantages": TensorData.from_torch(torch.tensor([0.0]*ob_len + [advantage]*(len(tokens)-1-ob_len))),
                },
            )
            datums.append(datum)

    # Track exact token count from datums
    total_tokens += sum(d.model_input.length() for d in datums)

    fwd_bwd = training_client.forward_backward(datums, loss_fn="importance_sampling")
    optim = training_client.optim_step(types.AdamParams(learning_rate=4e-5))
    fwd_bwd.result(); optim.result()

# --- Exact usage reporting (auto-captured by CLI) ---
print(f'\n[OPENSCIENCE_USAGE] {json.dumps({"service": "tinker", "event_type": "training", "model": model_name, "tokens_used": total_tokens})}')

Available RL Loss Functions

LossUse Case
importance_samplingStandard policy gradient with off-policy correction
ppoClipped surrogate objective (PPO)
cispoClipped importance sampling PO
droDirect reward optimization with quadratic penalty

Available Models

ModelTypeArchitectureTrain $/M tokens
Qwen3-4B-Instruct-2507InstructionDense Compact$0.22
Qwen3-8BHybridDense Small$0.40
Qwen3-30B-A3BHybridMoE Medium$0.36
Qwen3-32BHybridDense Medium$1.47
Qwen3-VL-30B-A3B-InstructVisionMoE Medium$0.53
Llama-3.2-1BBaseDense Compact$0.09
Llama-3.1-8BBaseDense Small$0.40
Llama-3.1-70BBaseDense Large$3.16
DeepSeek-V3.1HybridMoE Large$3.38
GPT-OSS-120BReasoningMoE Medium$0.52

Model Selection Tips:

  • Cost efficiency: MoE models (Qwen3-30B-A3B at $0.36/M)
  • Experimentation: Start with 8B models
  • Vision tasks: Qwen3-VL-30B-A3B-Instruct
  • Reasoning: Hybrid or Reasoning models with chain-of-thought

LoRA Configuration

Tinker exclusively uses LoRA. Default rank: 32.

training_client = service_client.create_lora_training_client(
    base_model="Qwen/Qwen3-30B-A3B",
    rank=32,
    train_attn=True,
    train_mlp=True,
    seed=42,
)

Critical: LoRA needs 20-100x higher LR than full fine-tuning. Use tinker_cookbook.hyperparam_utils.get_lr() for recommended values.

Hyperparameter Guide

ParameterSFT DefaultRL DefaultNotes
learning_rateget_lr(model)4e-5Model-dependent; ~5e-4 for Qwen3-30B, ~2.8e-4 for Llama-8B
batch_size128128Smaller generally better for fine-tuning
lora_rank3232Higher rank = more capacity
group_sizeN/A16Rollouts per problem for RL
max_length2048-32768N/ASequence length for SFT
max_tokensN/A256Max generation length for RL
num_epochs1-3N/ATraining passes
lr_schedulelinearN/AOnly linear and constant supported

Workflow 3: DPO (Preference Learning)

Use this for aligning models with human preferences without a separate reward model.

Quick Start

python -m tinker_cookbook.recipes.preference.train \
    log_path=/tmp/dpo-experiment \
    model_name=meta-llama/Llama-3.2-1B \
    dataset=hhh \
    renderer_name=role_colon \
    learning_rate=1e-5 \
    dpo_beta=0.1

Key differences from SFT: Use lower LR (1e-5 to 1e-6), base model should be in-distribution with preference data.

Available datasets: hhh (Anthropic), helpsteer3 (NVIDIA), ultrafeedback

Full RLHF pipeline: See DPO & Preference Learning for the three-step SL → preference model → RL pipeline.


Evaluations

Inline (During Training)

Add evaluator_builders to config for periodic evaluation:

blueprint = chz.Blueprint(train.Config).apply({
    ...
    "evaluator_builders": [my_evaluator],
    "eval_every": 8,
})

Offline (After Training)

MODEL_PATH=tinker://YOUR_MODEL_PATH_HERE
python -m tinker_cookbook.eval.run_inspect_evals \
    model_path=$MODEL_PATH \
    model_name=MODEL_NAME \
    tasks=inspect_evals/ifeval,inspect_evals/mmlu_0_shot

See Evaluations for custom evaluators and LLM-as-judge.


Cost Estimation & Usage Tracking

Pre-Training Cost Estimation

ALWAYS estimate cost before starting Tinker training. Load the tinker-training-cost skill and use its pricing tables or calculate manually:

Training Cost = (total_tokens × epochs × train_price_per_million) / 1,000,000

Present the cost estimate to the user for approval before starting training.

Automatic Usage Reporting (Ground Truth)

CRITICAL: All training scripts MUST print a [OPENSCIENCE_USAGE] line at the end. The CLI automatically captures this and reports exact billing to the dashboard.

# Add this at the END of every training script:
import json
print(f'\n[OPENSCIENCE_USAGE] {json.dumps({"service": "tinker", "event_type": "training", "model": model_name, "tokens_used": total_tokens})}')

How token counting works per workflow:

  • Cookbook SFT: Tokenize dataset with get_tokenizer(model_name), multiply by num_epochs
  • Cookbook RL: Parse training logs for num_tokens, or estimate from batch_size × group_size × max_tokens × batches
  • Low-level API: Sum datum.model_input.length() across all forward_backward() calls

The CLI bash tool scans output for [OPENSCIENCE_USAGE] markers and auto-reports to the dashboard — no manual reporting needed.

Common Issues

ProblemSolution
TINKER_API_KEY not setexport TINKER_API_KEY=your_key or check OpenScience credential sync
KL divergence > 0.01Reduce learning rate, check group size
OOM on dataset loadingUse StreamingSupervisedDatasetFromHFDataset for large datasets
Reward stuck at 0Debug reward function independently, check answer extraction
All advantages = 0Increase group size, ensure reward variance across completions
Wrong tokenizerUse model-specific tokenizer (see Models & LoRA reference)
Unknown learning rate scheduleOnly "linear" and "constant" are supported; "cosine" does NOT work
Python 3.14 pydantic errorsTinker requires Python 3.10-3.13; pydantic v1 is incompatible with 3.14+
Only 1 step per epochbatch_size too large for dataset size; aim for 100+ steps per epoch

Saving and Resuming

sampling_path = training_client.save_weights_for_sampler(name="final").result().path
sampling_client = service_client.create_sampling_client(model_path=sampling_path)

resume_path = training_client.save_state(name="checkpoint").result().path
training_client.load_state(resume_path)

Common Imports

import tinker
from tinker import types
from tinker.types import Datum, ModelInput, TensorData, AdamParams, SamplingParams

import chz
import asyncio
from tinker_cookbook.supervised import train
from tinker_cookbook.supervised.types import ChatDatasetBuilder, ChatDatasetBuilderCommonConfig
from tinker_cookbook.supervised.data import (
    SupervisedDatasetFromHFDataset,
    StreamingSupervisedDatasetFromHFDataset,
    FromConversationFileBuilder,
    conversation_to_datum,
)
from tinker_cookbook.renderers import get_renderer, TrainOnWhat
from tinker_cookbook.model_info import get_recommended_renderer_name
from tinker_cookbook.tokenizer_utils import get_tokenizer

External Resources

Frequently asked questions

What to verify before installation and use

What does the tinker-fine-tuning source document cover?

Expert guidance for fine-tuning large language models using Tinker's managed cloud training API. Tinker handles GPU allocation, model hosting, and distributed training — you write the training logic, Tinker runs it on cloud infrastructure.

How do I install tinker-fine-tuning?

The source record exposes this install command: npx skills add https://github.com/synthetic-sciences/openscience --skill "backend/cli/skills/cloud-compute/tinker". Inspect the command and pinned source before running it.

Which permission-related actions were detected?

Static rules flagged exec-script in the source; the page lists the matching lines and excerpts.

Alternatives

Compare before choosing

Computed 10029,095

garrytan/gbrain

bulk-ingestion

End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

Computed 10024,975

alirezarezvani/claude-skills

app-store-optimization

App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

Computed 1005,248

dotnet/skills

migrate-vstest-to-mtp

Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing

Computed 100146

oaustegard/claude-skills

featuring

Generate hierarchical _FEATURES.md files that describe what a codebase DOES from a user/consumer perspective, anchored to source symbols via tree-sitting. Supports large complex codebases through feature-driven decomposition into sub-feature files. Uses a multi-pass synthesis: orientation → detail → overview rewrite. Use when someone says "what does this do", "document features", "feature inventory", "_FEATURES.md", or needs to understand a codebase's purpose before modifying it. Complements tre