← Back to Index

Lesson 1

Steering - The Foundation

The Core Idea

Mental model: Steering files are persistent instructions that get injected into the model's context before you even type a message. They're the difference between telling Kiro your preferences every session vs. Kiro just knowing them.

Every time you start a chat, Kiro assembles a context window. Into that window go: the system prompt, your message, any files you reference, and - crucially - your steering files. These are markdown files that live in .kiro/steering/ and shape how Kiro behaves across all sessions in that workspace.

You've already seen one in action - the session-context.md in this very workspace is a steering file.

Where Steering Lives

There are two scopes:

ScopeLocationApplies to
Workspace.kiro/steering/*.mdThis workspace only
Global (User)~/.kiro/steering/*.mdEvery workspace you open

Only .md files directly in the steering/ folder are documented as being recognised - subdirectory support is not mentioned in official docs. To be safe, keep all steering files at the top level. Store supporting content (specs, schemas, reference docs) elsewhere in the workspace and reference them with #[[file:...]].

Global steering is for personal cross-project standards: "always use British English", "prefer functional patterns", "I use pnpm not npm". Workspace steering is for project-specific knowledge: "this is an Angular 18 app", "we use Tailwind", "API routes live in src/api/".

Precedence: If global and workspace steering conflict, workspace wins. Think of it like CSS specificity - more specific scope overrides the general.

The Three Inclusion Modes

This is the key thing most people don't realise: not all steering files are loaded all the time. There are three modes, controlled by YAML front-matter at the top of the file. The front-matter schema is tiny - just two keys, and that's the complete set:

KeyValuesRequired
inclusionauto | fileMatch | manualNo (defaults to auto if omitted)
fileMatchPatternA glob stringOnly when inclusion: fileMatch

That's it. No other front-matter keys exist for steering files. Here's what each mode does:

1. Always-on (default)

---
inclusion: auto
---

# My Coding Standards
Always use TypeScript strict mode...

No front-matter, or inclusion: auto - loaded into every single session, every message. Use this sparingly. Every token here costs you context space in every interaction.

Note: in practice, a rule that's purely about TypeScript would be better as fileMatch against **/*.ts so it doesn't load when you're working on CSS, HTML, or JSON. Reserve always-on for truly cross-cutting rules (naming conventions, tooling preferences, project-wide architecture).

2. Conditional (fileMatch)

---
inclusion: fileMatch
fileMatchPattern: "src/app/services/**/*.ts"
---

# API Layer Conventions
All HTTP services must use HttpClient with typed responses and handle errors with catchError...

Only loaded when Kiro reads a file matching the glob pattern. This is powerful - you can have detailed API conventions that only activate when you're working on API files. Zero cost when you're in the UI layer.

What "reads a file" means concretely: The trigger fires when a matching file enters the model's context window. This happens when: (1) Kiro's agent reads the file using its tools during a task, (2) you explicitly reference a matching file with #File in your message, or (3) the matching file is your active editor file. It does not trigger just because a matching file is open in a background tab - only when the file's content actually reaches Kiro.

3. Manual

---
inclusion: manual
---

# Database Migration Guide
When creating a new migration...

Never auto-loaded. You pull it in when you need it. Perfect for reference material that's too large to be always-on. There are two ways to invoke a manual steering file - both do the same thing (inject its content into context):

Different entry point, identical result: the file's content is added to your conversation context for that message. The only practical distinction is what else shows up in each menu - / lists skills alongside manual steering (things you invoke), while # lists files, folders, and other context keys like #Problems, #Terminal, #Git Diff alongside manual steering (things that add context). Pick whichever menu matches your mental framing at the time.

The file appears in these menus using its filename (minus the .md extension). There's no name property in the front-matter to override this - so if your file is .kiro/steering/db-migrations.md, it shows up as "db-migrations". Name your files descriptively.

In short: always, when a matching file is read, or when you ask for it.

Ad

File References: Pulling in External Content

Steering files can reference other files in your workspace using a special syntax:

Follow the API patterns defined in #[[file:docs/api-spec.yaml]]

This is Kiro-specific syntax, not standard markdown. Kiro intercepts this directive and expands it - replacing it with the referenced file's actual content before anything reaches the model. Standard markdown has no concept of #[[file:...]]. So steering files are markdown plus this one special directive.

When Kiro loads that steering file, it also loads the referenced file's content. This is how you can point Kiro at an OpenAPI spec, a GraphQL schema, a style guide, or any other document without pasting its contents into the steering file itself.

The path is relative to the workspace root.

Key distinction: Referenced files are just content embeds - they aren't steering files themselves and don't have their own inclusion modes. The inclusion mode of the parent steering file controls when everything loads. If the parent is always-on, all its referenced files are always-on. If the parent is fileMatch, the references only load when the match triggers. Referenced files have no independent say - they come along for the ride.

What Makes Good Steering

Steering files are injected raw into the context. Every word costs tokens. The best steering files are:

Anti-pattern: A single massive always-on steering file with everything. You're paying the full token cost on every message, even when working on something unrelated. Split into focused files and use appropriate inclusion modes.

A Practical Example

Here's how a real project might structure its steering:

.kiro/steering/
├── conventions.md          # Always-on: code style, naming, tooling
├── architecture.md         # Always-on: high-level structure, key patterns
├── api-standards.md        # fileMatch: "src/app/services/**/*.ts" — HTTP/API conventions
├── component-patterns.md   # fileMatch: "src/app/**/*.component.ts" — Angular component patterns
├── db-migrations.md        # Manual — only when doing migrations
└── deployment.md           # Manual — only when deploying

How Steering Relates to Everything Else

This is why we started here:

Quiz

You have a 200-line style guide that's only relevant when editing SCSS files. Which inclusion mode?

Always-on (auto)
Conditional (fileMatch with "**/*.scss")
Manual

You want a rule that applies in this workspace AND every other workspace you open. Where does the file go?

.kiro/steering/
~/.kiro/steering/
Either - they're equivalent

Your steering file references #[[file:docs/openapi.yaml]]. When is that YAML loaded?

Only when you explicitly open the YAML file
Whenever the steering file itself is loaded (based on its inclusion mode)
Once at workspace open, then cached

Your Tangible Win

You now understand the full mechanics of steering: three inclusion modes, two scopes, file references, and how it connects to every other Kiro feature. You can look at any .kiro/steering/ directory and immediately understand what's always-on, what's contextual, and what's on-demand.