> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Read what a session changed on disk

> The files this session's write, edit and delete tools changed, each with what it did to the file, how many lines moved, and the content the file held before the session first touched it. It is what a diff view of a session's own work stands on, and what a touched-files list shows counts from.
Every row is measured from FIRST touch. A file the session edited five times is one row comparing what it held before edit one against what is on disk now — not five rows, and not the last edit's delta. That is also why a file put back the way it was is absent from the answer: it changed nothing, and reporting it at zero lines either way would claim otherwise.
The current content is deliberately not served. The host and its clients share a filesystem, so a client reads the file itself and gets the version it is about to let somebody edit, rather than a copy that was already stale when it was sent. What only the host has is the before side.
Both sides are bounded at 1 MiB (1048576 bytes). Past that nothing was kept, and the row says so through beforeState rather than serving an empty file or a truncated one: beforeBytes still carries the real size, so a client can say how large the file it cannot diff is. linesAdded and linesRemoved are then absent, because a count nobody could compute is not zero.



## OpenAPI

````yaml /en/openapi/v3-current/narya.yaml get /v1/sessions/{sessionId}/changes
openapi: 3.1.0
info:
  title: Narya Host API
  version: 1.0.0
  description: >-
    The contract between the Narya host and every client. One long-lived host
    runs on your machine and serves this API over a Unix socket in your Narya
    home. Narya creates the socket owner-only, and file permissions are the
    whole authorization. There is no password, no token and no TLS. The terminal
    client and the one-shot command that Lerian ships drive this API, and a
    client you write drives the same one.


    Results never arrive on the response of the request that caused them.
    Submitting a message returns 202 with a turn id. Everything the turn
    produces streams over GET /v1/events as server-sent events with a typed
    envelope, and a stream resumes from a Last-Event-ID header.


    One error envelope: code, title, message, and fields on 422. Codes are NRY-
    followed by four digits. A paged list answers items, limit and a nextCursor
    when more remains. Cursors are opaque.
servers: []
security: []
tags:
  - name: host
    description: The host process itself — version, uptime, mode, store.
  - name: sessions
    description: Durable conversation containers. Archive, never destroy.
  - name: messages
    description: Submitting work into a session and interrupting it.
  - name: events
    description: The server-sent event stream every client consumes.
  - name: lanes
    description: Parallel tracks inside a session — main, subagent, side.
  - name: agents
    description: Named recipes — instructions, tools, model, policy. Read-only in v1.
  - name: ladder
    description: >-
      What a person can type: the skills and command files in force for one
      repository, and expanding one into text. Five origins merged, nearest
      winning a name, the repository's own rungs gated on trust.
  - name: permissions
    description: Pending permission asks, decisions, and the decision audit.
  - name: intercom
    description: Sessions on one machine finding and messaging each other.
  - name: packages
    description: The one thing a user installs — resources, Go code, or both.
  - name: workflows
    description: Deterministic multi-agent orchestration runs.
  - name: providers
    description: Model suppliers, their auth state, and the model catalogue.
  - name: monitors
    description: >-
      Long-running watchers a session keeps beside its conversation — a test
      runner in watch mode, a build, a log being followed. Started by the model
      or by the person, always listed, always killable.
  - name: records
    description: The queryable local record of everything that happened.
  - name: schedules
    description: >-
      Work the host's own clock starts with nobody present — a repository, a
      prompt, a rule and what one fire may spend. Cancel, never destroy.
paths:
  /v1/sessions/{sessionId}/changes:
    parameters:
      - $ref: '#/components/parameters/SessionIdParam'
    get:
      tags:
        - sessions
      summary: Read what a session changed on disk
      description: >-
        The files this session's write, edit and delete tools changed, each with
        what it did to the file, how many lines moved, and the content the file
        held before the session first touched it. It is what a diff view of a
        session's own work stands on, and what a touched-files list shows counts
        from.

        Every row is measured from FIRST touch. A file the session edited five
        times is one row comparing what it held before edit one against what is
        on disk now — not five rows, and not the last edit's delta. That is also
        why a file put back the way it was is absent from the answer: it changed
        nothing, and reporting it at zero lines either way would claim
        otherwise.

        The current content is deliberately not served. The host and its clients
        share a filesystem, so a client reads the file itself and gets the
        version it is about to let somebody edit, rather than a copy that was
        already stale when it was sent. What only the host has is the before
        side.

        Both sides are bounded at 1 MiB (1048576 bytes). Past that nothing was
        kept, and the row says so through beforeState rather than serving an
        empty file or a truncated one: beforeBytes still carries the real size,
        so a client can say how large the file it cannot diff is. linesAdded and
        linesRemoved are then absent, because a count nobody could compute is
        not zero.
      operationId: listSessionChanges
      parameters:
        - name: path
          in: query
          required: false
          description: >-
            Filter to one file, by the absolute path this operation reports for
            it, and serve that file's before content. Without it the answer
            covers every file the session changed and carries no content at all
            — a change list stays cheap, and the one file a diff view is opening
            is the one it asks for. A path this session never changed is an
            empty answer, not an error.
          schema:
            type: string
            maxLength: 4096
        - name: entryId
          in: query
          required: false
          description: >-
            Answer for ONE step of the conversation instead of for the session:
            what the tool call recorded on this entry did to each file it
            mutated, measured from the restore point taken before that entry to
            the one taken at it. Both sides are then served (beforeContent and
            afterContent), because the after side is a moment that has since
            been edited over and nothing on disk remembers it. It exists because
            the session-scoped answer above is the wrong one under an old
            receipt: a file edited five times has one row carrying all five
            edits, so drawing it under the first receipt credits that call with
            every line that came after it. An entry whose step mutated nothing
            is an empty answer, not an error, and a step the host never
            snapshotted comes back with beforeState "too-large" — nothing was
            kept — rather than as an empty diff. path and entryId are not
            combined; entryId wins when both are given.
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: The files this session changed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FileChangeSet'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  parameters:
    SessionIdParam:
      name: sessionId
      in: path
      required: true
      description: The session's id.
      schema:
        type: string
        format: uuid
  schemas:
    FileChangeSet:
      type: object
      description: >-
        Every file a session changed, in the order the session first met them.
        Not paginated: the set is bounded by what one conversation's tools
        actually mutated, and a client that wants one file asks for it by path.
      required:
        - items
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/FileChange'
      examples:
        - items:
            - path: /home/dev/ledger/validate.go
              op: modified
              beforeState: text
              beforeBytes: 4211
              linesAdded: 12
              linesRemoved: 3
    FileChange:
      type: object
      description: >-
        One file a session changed, measured from the content it held when the
        session first touched it to what is on disk now.
      required:
        - path
        - op
        - beforeState
        - beforeBytes
      properties:
        path:
          type: string
          description: The file's absolute path.
        op:
          type: string
          enum:
            - added
            - modified
            - deleted
            - renamed
          x-enum-varnames:
            - FileChangeOpAdded
            - FileChangeOpModified
            - FileChangeOpDeleted
            - FileChangeOpRenamed
          description: >-
            What the session did to the file, at file granularity: it was not
            there and now is, it was there and changed, it was there and is
            gone, or it is the same bytes under another name. This is the
            file-level fact a change list shows, not the per-call
            read/write/edit a tool receipt carries.

            renamed is reported only where it can be known for certain and costs
            nothing to know: inside one change set, a file that went and a file
            that arrived whose content is byte-identical are one row naming both
            paths, and previousPath carries the name it had. There is no rename
            DETECTION behind this — no git, no similarity score — so a file that
            was moved AND edited is still reported as an added row beside a
            deleted one, which is what a reader without this value gets for
            every move. A client that does not know the value degrades to
            whatever it draws for an op it cannot name.
        beforeState:
          type: string
          enum:
            - absent
            - text
            - not-text
            - too-large
          x-enum-varnames:
            - FileChangeBeforeStateAbsent
            - FileChangeBeforeStateText
            - FileChangeBeforeStateNotText
            - FileChangeBeforeStateTooLarge
          description: >-
            What is known about the content the file held before the session
            changed it, so an unavailable diff is never mistaken for an empty
            one. absent — the file did not exist, and the whole of it is added.
            text — beforeContent carries it when this read asked about a single
            path. not-text — the bytes were kept but are not valid UTF-8, so
            they are never served as a string and no line count over them would
            mean anything. too-large — the file was past the 1 MiB bound and
            nothing was kept; beforeBytes says how large it was.
        beforeBytes:
          type: integer
          format: int64
          minimum: 0
          description: >-
            The file's size when the session first touched it, 0 when it did not
            exist. True even when the content itself was too large to keep.
        beforeContent:
          type: string
          description: >-
            The content the file held before the session changed it. Present
            only when the request named a single path or one entry AND
            beforeState is text or absent — a file the step created has no
            before side, so absent pairs with the empty string here, which is
            the side a created file is diffed against. A client diffs it against
            the file it reads from disk itself, and edits the second side.
        afterContent:
          type: string
          description: >-
            The other side, present only on an entryId read. A session-scoped
            change is measured against the file on disk, which the client shares
            and reads itself; one step's change ends at a moment that has since
            been edited over, so the host serves both ends or the diff cannot be
            drawn at all.
        linesAdded:
          type: integer
          minimum: 0
          description: >-
            Lines this session added, counted from the before content against
            the file as it is now. Absent when no diff could be computed — see
            beforeState — because a count nobody could compute is not zero.
        linesRemoved:
          type: integer
          minimum: 0
          description: Lines this session removed, on the same terms as linesAdded.
        previousPath:
          type: string
          description: >-
            The absolute path the file had before the session moved it, on a
            renamed row and nowhere else. path is where the file is now, so a
            reader states the move from the two together. The row's before side
            — beforeState, beforeBytes, beforeContent — belongs to this path,
            since that is the file the content was measured from.
      examples:
        - path: /home/dev/ledger/validate.go
          op: modified
          beforeState: text
          beforeBytes: 4211
          beforeContent: |
            package ledger
          linesAdded: 12
          linesRemoved: 3
    Error:
      type: object
      description: >-
        The single error envelope every operation returns. Codes are NRY-
        followed by four digits and are catalogued in the top-level
        x-error-catalog extension. fields appears only on 422 validation errors,
        mapping each offending property to its problem.
      required:
        - code
        - title
        - message
      properties:
        code:
          type: string
          pattern: ^NRY-[0-9]{4}$
          description: Machine-readable error code from the NRY catalogue.
        title:
          type: string
          maxLength: 256
          description: Short human-readable summary of the error class.
        message:
          type: string
          maxLength: 4096
          description: Specific, actionable description of what went wrong.
        fields:
          type: object
          description: Per-field validation problems. Present on 422 only.
          additionalProperties:
            type: string
      examples:
        - code: NRY-0002
          title: Session not found
          message: >-
            No session with id 6b9f6d2e-1c3a-4f5b-9d7e-2a8c4e6f0b1d exists on
            this host.
  responses:
    BadRequest:
      description: Malformed request — invalid parameter, cursor, or JSON body.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: The addressed resource does not exist on this host.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalServerError:
      description: The host failed — including a store that refuses writes (NRY-0012).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

````