Skip to content
Back to top
View this page
Edit this page

# Xonsh Session

When xonsh starts, it builds a long-lived session object that holds the environment, history, command pipeline, parser, executor, jobs and so on. Two Python objects expose this state:

- `xonsh.built_ins.XonshSessionInterface` — a small, stable surface intended for end users and scripts. Reachable through the `@` shortcut (`@.env`, `@.history`, `@.imp`, `@.lastcmd`).

- `xonsh.built_ins.XonshSession` — the internal session container with everything xonsh needs at runtime. Reachable as `__xonsh__` (or `xonsh.built_ins.XSH`). Useful when you are extending xonsh, writing completers, hooks, or low-level integrations.

This page documents both, with a focus on day-to-day use cases.

## `XonshSessionInterface` and the `@` shortcut

`XonshSessionInterface` is the public, narrow surface of a xonsh session. It is exposed as a single-character shortcut: the `@` token.

Internally, the parser rewrites every `@.<name>` into `__xonsh__.interface.<name>`, so the two are exactly equivalent. `@` on its own evaluates to the interface object itself.

This means you can use `@` directly inside Python and subprocess mode:

    # Print the value of $HOME via the typed Env API
    echo @(@.env.get('HOME', '/tmp'))

    # Last exit code
    echo "exit was" @(@.lastcmd.rtn)

    # Inline import + call in one expression
    echo @(@.imp.json.dumps({'ok': True}))

### `@.env` — current environment

`@.env` is the current `xonsh.environ.Env` instance. Use it any time you want a programmatic, typed read or write of an environment variable, instead of the shell-style `$VAR` form.

Use cases:

    # Safe lookup with default
    home = @.env.get('HOME', '/tmp')

    # Temporary override scoped to a `with`-block — restored on exit
    with @.env.swap(EDITOR='vi', PAGER='cat'):
        $[git log --oneline -3]

    # Register a custom env variable with a validator and default
    @.env.register('MY_TIMEOUT', type='int', default=30,
                   doc='Request timeout in seconds.')

`@.env` shines when the variable name is dynamic (built from a string) and you need default value, since `$VAR` requires a literal name in the source.

### `@.history` — history backend

`@.history` is the active `xonsh.history.History` backend (`json`, `sqlite`, or `dummy`). It exposes the same API regardless of the configured backend.

Use cases:

    # Last command typed in this session (raw input)
    print(@.history.inps[-1])

    # Iterate session items: each is {'inp': cmd, 'ts': (start, end)}
    for item in @.history.items():
        print(item['inp'])

    # All history (across sessions)
    for item in @.history.all_items(newest_first=True):
        print(item['inp'])
        break

    # Force a flush to disk (same as `history flush`)
    @.history.flush()

The `history` xonsh command is the user-facing wrapper around this object. `@.history` is what you reach for when you need data, not text.

### `@.imp` — inline importer

`@.imp` is an `xonsh.built_ins.InlineImporter` instance. It turns `@.imp.<module>` into `__import__('<module>')` on first attribute access, so you can pull in and use a stdlib (or third-party) module without a separate `import` line.

Use cases:

    # One-liners that would otherwise need an import
    echo @(@.imp.time.time())
    echo @(@.imp.json.dumps({'pid': @.imp.os.getpid()}))
    echo @(@.imp.platform.system())

    # Pipe a Python value into a subprocess
    echo @(@.imp.uuid.uuid4()) | tr - _

    # Handy for startup aliases — no upfront import needed
    aliases['epoch'] = lambda args: print(int(@.imp.time.time()))

For repeated use of the same module, a regular `import` is faster and clearer; `@.imp` is for ad-hoc, one-shot calls where adding an `import` would just be noise.

### `@.lastcmd` — last command pipeline

`@.lastcmd` is the `xonsh.procs.pipelines.CommandPipeline` of the most recently completed subprocess-mode command. It is updated every time you run a subprocess (`ls`, `$(...)`, `![...]`, etc.).

Use cases:

    ls /nope
    print('exit:', @.lastcmd.rtn)        # exit code
    print('stdout:', @.lastcmd.output)   # captured stdout (if any)
    print('stderr:', @.lastcmd.errors)   # captured stderr (if any)
    print('args:',   @.lastcmd.args)     # the parsed command list
    print('alias:',  @.lastcmd.alias)    # alias resolved (if any)

    # Build a "fail fast" wrapper in a script
    git pull
    if @.lastcmd.rtn != 0:
        raise SystemExit('git pull failed')

## `XonshSession` — the internal session

`XonshSession` is the full container that xonsh builds at startup. It is reachable in two equivalent ways:

- `__xonsh__` — bound into `builtins` when the session loads, so every executed scope sees it as a global.

- `xonsh.built_ins.XSH` — the canonical module-level singleton.

Warning

Most attributes here are internal. They are exposed because xonsh needs them to talk to itself, but they are not part of the stable API. Anything in `XonshSessionInterface` (the `@` shortcut) is meant to outlive releases; everything else here may change. Prefer `@.<x>` or `XSH.interface` whenever an equivalent exists.

### Useful fields

The following attributes are the most commonly used by hooks, completers, and xonsh RC automation. They are listed roughly in the order you are likely to need them.

- `__xonsh__.env` — same `xonsh.environ.Env` as `@.env`; populated by `XonshSession.load()`.

- `__xonsh__.history` — same as `@.history`.

- `__xonsh__.aliases` — the live `xonsh.aliases.Aliases` mapping. Setting `__xonsh__.aliases['ll'] = 'ls -la'` from your xonsh RC is the canonical way to define an alias. The property delegates to `commands_cache.aliases` and is read-only on the session itself; mutate the mapping in place.

- `__xonsh__.completers` — `OrderedDict` of registered completer callables. Lazily initialized on first access. Modify with the `completer` command or by mutating the dict directly.

- `__xonsh__.shell` — the active shell wrapper (`xonsh.shell.Shell`). The concrete implementation is in `__xonsh__.shell.shell` (`PromptToolkitShell`, `ReadlineShell` or `DumbShell`). Use this when you need to call a shell-specific method like `print_color`.

- `__xonsh__.execer` — the `xonsh.execer.Execer`, which parses, compiles, and runs xonsh source. Use `execer.exec(src)` / `execer.eval(src)` to evaluate xonsh code from inside Python.

- `__xonsh__.builtins` — a `SimpleNamespace` containing the xonsh-injected builtins: `XonshError`, `XonshCalledProcessError`, `evalx`, `execx`, `compilex`, `events`, `print_color`, `printx`.

- `__xonsh__.ctx` — the global Python context dict that all xonsh user code runs against. Equivalent to `globals()` for the REPL. Useful for completers and hooks that want to inspect what the user has defined.

- `__xonsh__.all_jobs` — dict of background jobs keyed by job id. See `jobs`, `fg`, `bg`.

- `__xonsh__.lastcmd` — same as `@.lastcmd`.

- `__xonsh__.sessionid` — UUID of the current session, used in history filenames and similar.

- `__xonsh__.rc_files` — list of xonsh RC files actually loaded.

- `__xonsh__.builtins.events` — the `xonsh.events.events` registry; how you subscribe to `on_postcommand`, `on_pre_prompt`, `on_chdir` and friends.

- `__xonsh__.exit` — set this to an integer from anywhere to ask xonsh to exit on the next loop iteration with that return code.

### Lifecycle and helpers

These are the methods you call when embedding xonsh, hot-reloading the session in tests, or writing tooling that wraps it:

- `load(execer=None, ctx=None, inherit_env=True, **kwargs)` — fully initialize the session: build the env, install builtins into Python, hook `atexit` for history flush, install signal handlers. Called by `main.main_xonsh` once at startup.

- `unload()` — reverse of `load`: undo env replacement, restore Python’s `exit`/`quit`, flush history, remove `__xonsh__` from builtins.

- `link_builtins()` / `unlink_builtins()` — rebind the proxy builtins (`XonshError`, `events`, etc.) into Python’s `builtins` namespace. Used internally by `load`/`unload`.

- `cmd(*args, **kwargs)` — return a `xonsh.built_ins.Cmd` builder that lets you compose a subprocess pipeline programmatically before dispatching it. See the next section.

### Subprocess dispatchers — how `$()`, `!()`, `$[]`, `![]` map to Python

Every subprocess-mode operator in xonsh is a thin parser sugar around a `XonshSession.subproc_*` method. Knowing the mapping is what lets you construct commands programmatically (for example from a list of arguments) and still get exactly the same semantics as the literal form.

Syntax | Method | Returns | Use it when
--- | --- | --- | ---
`$(cmd)` | `__xonsh__.subproc_captured_stdout` | `str` (or `list[str]` if `$XONSH_SUBPROC_OUTPUT_FORMAT='list_lines'`) | You only want the captured stdout as a value to assign, interpolate, or pass on.
`!(cmd)` | `__xonsh__.subproc_captured_object` | `xonsh.procs.pipelines.CommandPipeline` | You want the whole result object: exit code, stdout, stderr, timing, alias info. Truthy iff `rtn == 0`.
`$[cmd]` | `__xonsh__.subproc_uncaptured` | `None` | You want output to go straight to the terminal with no capture. The “just run it” form.
`![cmd]` | `__xonsh__.subproc_captured_hiddenobject` | `xonsh.procs.pipelines.HiddenCommandPipeline` | Like `!()` but the object’s `repr` does not dump the captured output to the screen. Useful inside hooks/scripts.
`@$(cmd)` | `__xonsh__.subproc_captured_inject` | `list[str]` | You want the captured stdout split via xonsh’s lexer (so it respects quoting) and spliced as arguments into another command.

All of these forms accept the same `cmds` shape:

- `cmds` is a list of “commands”, each command being a list of argument strings/tuples.

- Multiple commands separated by `"|"` form a pipe.

- A trailing `"&"` runs the pipeline in the background.

So `$(ls -la | grep .py)` becomes `subproc_captured_stdout(['ls', '-la'], '|', ['grep', '.py'])`.

This is exactly what the `xonsh.built_ins.Cmd` builder produces, which is why you can write the same pipeline two ways:

    # As literal subprocess sugar
    out = $(git log --oneline -5 | head -3)

    # Or built explicitly via the Cmd helper
    out = (
        @.imp.xonsh.built_ins
        .Cmd(__xonsh__, 'git', 'log', '--oneline', '-5')
        .pipe('head', '-3')
        .out()    # dispatches to subproc_captured_stdout
    )

Other dispatch helpers on the builder map 1:1 to the table above:

- `Cmd.out()` → `$()` (`subproc_captured_stdout`)

- `Cmd.run()` → `$[]` (`subproc_uncaptured`)

- `Cmd.obj()` → `!()` (`subproc_captured_object`)

- `Cmd.hide()` → `![]` (`subproc_captured_hiddenobject`)

Use the literal forms in interactive code, and the dispatcher / builder API when the command list is dynamic — for example built from user input, generated in a loop, or driven by config.

### Other AST-invoked helpers

A few more attributes on `__xonsh__` exist because xonsh’s parser rewrites special syntax into calls on them. You normally do not call these directly, but it is useful to know they are there:

- `pathsearch` / `globsearch` / `regexsearch` / `regexmatchsearch` — implement backtick expressions (``regex``, `g`glob``, etc.) and `$VAR` glob expansion.

- `glob` — wrapper used by glob expansion in subproc mode.

- `expand_path` — applied to bare path arguments.

- `call_macro` / `enter_macro` — power xonsh macro calls (`f!(...)`) and macro context managers.

- `path_literal` — backs the `p"..."` Path literal syntax.

- `help` / `superhelp` — back `obj?` and `obj??` for Python objects (the subproc-mode counterparts live in `xonsh.procs.specs` and `xonsh.aliases.print_alias_help`).

- `eval_fstring_field` — backs xonsh’s f-string field evaluation.

- `list_of_strs_or_callables` / `list_of_list_of_strs_outer_product` — flatten the heterogeneous argument lists xonsh’s parser produces before dispatching to subproc.

When in doubt, prefer `@.<x>` (`XSH.interface`) for the four stable bits of the API, and treat everything on `__xonsh__` as power-user territory that should be guarded with try/except and feature checks.

## See also

- Environment – environment variables and `@.env`

- Subprocess – subprocess operators backed by session attributes

- Built-in Aliases – `@.aliases` and alias management

- Built-in Events – event system and handler registration