Pages

Wednesday, 3 June 2026

Some notes on LLMs

 

What does e.g. 1M context mean in a model description?


"1M context" means the model can handle up to 1 million tokens in its context window — the combined input (your messages, files, tool results, system prompt) plus output it can consider at once. For reference, that's roughly 750,000 words or a few thousand pages of text, letting it work with very large codebases or long conversations without losing earlier content.

What is a LLM's tool-use loop? 


An LLM tool-use loop is the pattern where you let a language model drive an investigation by repeatedly choosing tools to call, rather than answering in one shot.

The shape


  1. Send: system prompt + user request + list of available tools (with JSON schemas)
  2. Model responds with either:
       (a) a final text answer  -> exit loop
       (b) a "tool_use" block: { name: "run_aws_cli", input: { args: [...] } }
  3. Your code executes that tool, captures the result
  4. Append the tool result to the conversation as a "tool_result" message
  5. Send the whole conversation back to the model
  6. Goto 2

The model never executes anything itself — it just emits requests to call tools. Your code is the runtime that actually runs them and feeds the output back.

Why it's a loop

Each turn the model sees everything it has learned so far (prior tool calls + their outputs) and decides the next step based on that. So a real run looks like:

  - Turn 1: model calls cloudwatch describe-alarms --state-value ALARM
  - Turn 2: sees 3 alarms, picks the noisiest, calls logs filter-log-events for that log group around the alarm time
  - Turn 3: sees an error pattern, calls kubectl describe pod on the affected workload
  - Turn 4: emits final Markdown report, no tool call → loop exits

  The model is doing the planning; your code is the dispatcher.

Why you need a budget

Without limits the loop can spin forever — the model keeps finding "one more thing to check." Hence in agent.run():

  - max_iterations=30 — hard cap on turns
  - max_tokens_per_turn=12288 — cap on a single response
  - Per-tool wall-clock timeouts (60 s for CLI, 30 s for HTTP)
  - Output truncation (50 000 char stdout) so a giant tool result doesn't blow the context window

How it ends

The loop terminates when the model returns a response with no tool_use block — that's the "I'm done, here's the answer" signal (stop_reason: end_turn). Or when you hit a budget limit and force-stop it.

Where the safety lives

Because the model can ask for arbitrary tool calls, the loop is only as safe as the tool implementations. That's why when implementing agents we should have the allowlists (services, verbs, paths) - the model can request aws s3 rm, but the validator rejects it before subprocess.run ever sees it.

The "two-pass" design in agent is a refinement: pass 1 is a tool-use loop (gather), pass 2 is a single non-loop call (synthesize). Splitting them lets each prompt focus on one job.


What are those .md files used by AI Agents?


There isn't a universally agreed official name, but people commonly refer to files like CLAUDE.md, GEMINI.md, AGENTS.md, COPILOT_INSTRUCTIONS.md, and .cursorrules as:

  • AI agent instruction files (most generic)
  • Agent configuration files
  • Agent context files
  • LLM instruction files
  • Repository AI instructions
  • Project AI guidelines

In the developer tooling community, "agent instructions" or "agent context files" are probably the most widely understood umbrella terms.

For example:

Tool             File
----               -----
Claude Code       CLAUDE.md
Gemini CLI       GEMINI.md
GitHub Copilot   .github/copilot-instructions.md
OpenAI Codex CLI   AGENTS.md
Cursor             .cursorrules / project rules
Windsurf          Rules files

Collectively, you could describe them as:

"Repository-level AI agent instruction files that provide persistent context and operating rules for coding assistants."

If you're building tooling around them (e.g., in your DevOps work), I'd recommend using "agent instructions" as the generic term because it's vendor-neutral and easily understood across Claude, Gemini, Copilot, Cursor, Codex, and similar tools.



Introduction to Claude by Anthropic




How to give Claude an instruction to apply label "DevOps" whenever it creates a new Linear ticket?



It depends on whether you're creating Linear tickets via:
  • Linear MCP,
  • a custom /create-ticket command,
  • or just asking Claude in chat to create tickets
The best location depends on which of those you're using.


If you're just asking Claude in chat to create tickets: if you want this behavior for all projects, put it in:

~/.claude/CLAUDE.md

If you want it only for a specific repository/project, put it in:

<repo-root>/CLAUDE.md

If you want it only for yourself in a specific project (without committing it to git), put it in:

<repo-root>/CLAUDE.local.md

CLAUDE.local.md is usually the best place for personal workflow preferences like Linear labels. Claude loads it after the project-level file, so your preference is read later and tends to have more influence.

For example:

## Linear Ticket Creation

When creating new Linear issues:

- Always apply the "DevOps" label.
- If multiple labels are appropriate, include "DevOps" in addition to the others.
- Verify the label exists before creating the issue.

If you're creating tickets through a custom slash command (e.g. /create-ticket) or a Linear MCP workflow, an even more reliable approach is to put the instruction directly in the command definition under:

~/.claude/commands/create-ticket.md

or in a dedicated skill, because the instruction is then attached specifically to the ticket-creation workflow rather than relying on general memory. Many Claude Code users find workflow-specific commands more reliable than large global CLAUDE.md files for things like Linear automation.


How to instruct Claude to use feature branch name from a Linear ticket when implementing it?


Add a specific workflow rule to CLAUDE.md rather than a vague instruction. Claude follows procedural instructions much more reliably.

For example:

## Linear Ticket Workflow

When implementing work from a Linear ticket:

1. Retrieve the ticket details from Linear.
2. Check whether the ticket has a suggested branch name.
3. Before making any code changes, switch to or create a git branch using the Linear branch name.
4. Do not create an alternative branch name unless the Linear branch name is unavailable.
5. If the branch already exists remotely, check it out instead of creating a new branch.
6. Confirm the branch name being used before starting implementation.

Example:

Linear ticket: DEV-123 Add deployment health checks
Branch: bojan/dev-123-add-deployment-health-checks

Commands:

git fetch origin
git checkout bojan/dev-123-add-deployment-health-checks || \
git checkout -b bojan/dev-123-add-deployment-health-checks

If you're using the Linear MCP server, I'd make it even more explicit:

## Branch Naming

For any task originating from Linear:

- Always obtain the branch name from the Linear ticket metadata.
- Never invent a branch name if Linear provides one.
- Use the Linear-provided branch name exactly as written.
- Checkout the branch before planning or implementing changes.

An even better approach is to create a dedicated command such as .claude/commands/implement-ticket.md:

Given a Linear ticket ID:

1. Load the ticket.
2. Read the ticket's branch name.
3. Checkout the branch.
4. Implement the work.
5. Commit using the ticket ID in the commit message.

Workflow-specific commands tend to be more reliable than relying on global instructions in CLAUDE.md, especially for things like branch creation, ticket labeling, and PR naming.


If I update ~/.claude/CLAUDE.md, do I need to start the new Claude session?


Usually no restart is strictly required, but it depends on how you’re using Claude:

If you’re using Claude Code / CLI (most common case)


~/.claude/CLAUDE.md is typically read when a new session starts

So:
✅ New terminal session / new Claude run → picks up changes
⚠️ Already-running interactive session → may not reliably reload it

Best practice: restart the Claude session (or re-open the CLI/chat) after changing it if you want to be sure the new rules apply.

If you’re using a long-running agent session


(e.g. an ongoing “Claude is working in the repo” process)

It often caches the instructions in memory at session start
So updates won’t consistently apply mid-task

If you’re using repo-level CLAUDE.md


Same rule: loaded at session start or project initialization
Changes apply reliably on next session or re-attach to repo

Practical rule of thumb


Changed CLAUDE.md → start a new Claude session to guarantee it applies
Minor edits while actively working → assume they won’t fully apply until restart


How to add auto-generated instructions to global context?

During Claude Code session, it created two memories but they were bound to the current project only:

Write(/Users/bojan/.claude/projects/-Users-bojan-repos-Company-Project/memory/gh-token-unset.md)
  ⎿  Wrote 10 lines to /Users/bojan/.claude/projects/-Users-bojan-repos-Company-Project/memory/gh-token-unset.md
       1 ---
       2 name: gh-token-unset
       3 description: gh CLI fails with HTTP 401 Bad credentials unless GH_TOKEN is unset first
       4 metadata:
       5   node_type: memory
       6   type: reference
       7   originSessionId: 9xxx6
       8 ---
       9
      10 In this environment `gh` fails with `HTTP 401: Bad credentials` because a stale `GH_TOKEN` env var overrides the working keyring auth. Run `unset GH_TOKEN` in the same Bash command before any `gh`
          call — the keyring account (`BojanKomazec`, scopes gist/read:org/repo) then works. Env doesn't persist between Bash calls, so include the `unset` each time.

⏺ Write(/Users/bojan/.claude/projects/-Users-bojan-repos-Company-Project/memory/precommit-hook-needs-no-verify.md)
  ⎿  Wrote 10 lines to /Users/bojan/.claude/projects/-Users-bojan-repos-Company-Project/memory/precommit-hook-needs-no-verify.md
       1 ---
       2 name: precommit-hook-needs-no-verify
       3 description: git commit aborts in non-interactive shell; the pre-commit hook prompts on /dev/tty
       4 metadata:
       5   node_type: memory
       6   type: reference
       7   originSessionId: 9xxx6
       8 ---
       9
      10 The global pre-commit hook (`~/.git-templates/hooks/pre-commit`) prompts interactively via `/dev/tty` ("view diff? proceed with commit?"). In a non-interactive shell it errors `/dev/tty: Device no
         t configured` and aborts the commit. Use `git commit --no-verify` to bypass it when committing programmatically.

⏺ Write(/Users/bojan/.claude/projects/-Users-bojan-repos-Company-Project/memory/MEMORY.md)
  ⎿  Wrote 2 lines to /Users/bojan/.claude/projects/-Users-bojan-repos-Company-Project/memory/MEMORY.md
      1 - [gh token unset](gh-token-unset.md) — `unset GH_TOKEN` before any `gh` command or it 401s
      2 - [pre-commit hook needs --no-verify](precommit-hook-needs-no-verify.md) — commit hook prompts on /dev/tty, aborts non-interactively

What you’re looking at in:

~/.claude/projects/.../memory/MEMORY.md

is project-scoped learned memory (auto-generated runtime notes), not the best place to define global rules.

To make something apply to all projects, you should put it in:

~/.claude/CLAUDE.md

How to structure it properly


Think of ~/.claude/CLAUDE.md as your global “agent operating system”.

You can directly migrate those MEMORY.md rules into it like this:

## Global DevOps / CLI Behavior Rules

These rules apply to all projects unless explicitly overridden.

### GitHub CLI
- Always run `unset GH_TOKEN` before executing any `gh` command.
- Reason: GH_TOKEN causes 401 errors in local CLI authentication.

### Git commits
- When committing changes, always use `--no-verify`.
- Reason: pre-commit hooks may attempt interactive prompts via /dev/tty and break non-interactive runs.


Important distinction (this is the key part)


File               Scope                 Who writes it Purpose
----                  -----                  -------------    --------
~/.claude/CLAUDE.md  Global (all projects) You             Your permanent rules
<repo>/CLAUDE.md      Per project             You/team         Repo-specific rules
~/.claude/projects/.../MEMORY.md Auto-generated Claude     Learned behavior, not authoritative

👉 Never manually “promote” MEMORY.md as your source of truth
Instead, copy stable patterns into ~/.claude/CLAUDE.md.

For your Linear branch-name requirement


You’d add it here too:

## Linear Workflow (Global)

When working from Linear tickets:
- Always use the branch name provided by Linear metadata.
- Never generate custom branch names.
- Always checkout the Linear branch before implementation.


One extra improvement (worth doing)


If you want this to be really robust, structure your global file like:

~/.claude/CLAUDE.md
├── Git / GitHub rules
├── Linear workflow rules
├── Shell safety rules
├── CI/CD rules

Claude responds better to clear domains than long flat lists.