Organization

Kestrel programs are made of modules. A module is a unit of code with its own namespace; modules are made of files; files declare which module they belong to and import names from other modules.

Modules

Every .ks file starts with a module declaration:

module Game.Player // ...declarations live here

The module name is dotted to suggest hierarchy — Game.Player is conceptually inside Game. Hierarchy here is naming convention; modules are otherwise flat. A program can have many files in one module; all declarations across those files share the namespace.

A common shape for a small project:

src/ main.ksmodule Main game.ksmodule Game player.ksmodule Game.Player enemy.ksmodule Game.Enemy

Visibility

Four levels:

public struct Account { public func openToEveryone() {} internal func sameModuleOnly() {} // default fileprivate func sameFileOnly() {} private func sameDeclarationOnly() {} }

internal is the default — if you don't write a modifier, that's what you get. public is opt-in: anything you want callable from another module needs public on it. fileprivate restricts to the file it's declared in. private restricts to the enclosing declaration — an extend block outside the struct body can't access private fields, but can access fileprivate ones.

The same modifiers apply to types, fields, methods, and protocol requirements. A public func on an internal struct is still only reachable from the module — visibility is the minimum of the chain.

Imports

import brings names from another module into scope:

import std.io.stdio.println import std.collections.Dictionary

You can import a specific name (as above) or a whole module:

import std.collections // brings the module in; reference as Dictionary, Array, ...

The Kestrel standard library auto-imports its most-used names — Int, String, Bool, Optional, Result, Array, etc. You shouldn't need to write import std.num.Int manually; if a basic name resolves, it's because the prelude already imported it.

Import only what you use. Wildcards aren't supported; if you want every name from a module, import the module itself and use the prefix.

A complete example

// game/player.ks module Game.Player import std.io.stdio.println public struct Player { public let name: String public var hp: Int } extend Player { public mutating func takeDamage(amount: Int) { self.hp = self.hp - amount; println("\(self.name) takes \(amount) damage"); } } <!-- sample: skip --> // main.ks module Main import Game.Player.Player @main func main() { var p = Player(name: "Morgana", hp: 100); p.takeDamage(25); }