tinymind~/research/tinymindAll projects

Type a section name and press Enter. Use “help” for the list.

Figures: softened for dark viewingDisplay only; image files are unchanged.
← The work

Project record · Reviewed October 9, 2026

TinyMind / Saoirse

Can an agent learn which questions and actions are worth pursuing?

Current stateContinuing graph-based agent with outcome-sensitive curiosity and inspectable ledgers

Approach

TinyMind develops Saoirse as a continuing agent whose retained knowledge helps determine what she attends to and does next. The graph holds concepts, relations, sources, and a model of herself. The longer-term aim is for her drives and capabilities to become revisable knowledge too, so experience can change more than the answers she retrieves.

She reads, extracts relations, notices gaps, and selects investigations within a daily budget. Recent work temporarily reduces attention to the graph regions it touched; that attention recovers over time. Separately, a resolution ledger measures whether each investigation reduced the gap that motivated it, and productive kinds of investigation receive more weight in future choices. Her graph, attention, attempts, and cooldowns persist across restarts.

Why this approach

An interest needs an outcome it can learn from

A graph can keep growing while an agent repeats the same investigation. The useful feedback is whether the particular gap that motivated an action became smaller. That led to goal-specific deficit measures, proportional refunds, cooldowns, and a payoff estimate used when choosing goals.

These are still structural proxies. A relation supplied by an extractor can reduce a graph deficit without making the retained account more accurate. The prediction and contradiction work asks how to connect those internal changes to evidence that can disagree.

Let capabilities become usable knowledge

The next design question is whether the agent can discover and compose what she can do through the same retained structure she uses for other knowledge. The current action selector still contains fixed cases. Representing capabilities and their preconditions in the graph is a documented direction, with reliable outcome and trust signals needed before it can support broader autonomy.

The longer-term attention design also distinguishes a lasting disposition toward something from a temporary state of boredom or fascination. That remains a design question. The implemented regional attention mechanism responds to recent activity; lasting preferences remain untested.

Where it stands

The reading path turns incoming material into graph concepts and relations with confidence and source information. Provenance distinguishes outside reading, user input, reflection, and deduction. Source nodes retain trust that can influence the confidence of later extractions; relation nodes can carry properties used by deduction.

Saoirse also has a persistent self-description. A self-directed goal can ask a language model to reconsider that description from her recent activity and connect her self node to concepts she already knows. These links enter the same graph used by clustering and curiosity. The initial description was supplied by me; the implemented update path is a way to investigate how a self-model develops.

Reflection can feed new relations back into the graph, and reasons for rejecting an outward draft can enter as user corrections. Maintenance jobs surface possible duplicates and structural problems for later attention. An audit goal can then investigate a pair or decide whether to merge it, retaining a record when two concepts should stay distinct.

An optional deduction job records derived claims and their premises in a prediction ledger, then checks later graph evidence for corroboration or contradiction. Inferred edges are excluded from the structural measure that earns investigation refunds, preventing the agent from paying herself merely for expanding deductions.

The continuing loop, attention, budget, and outcome-sensitive priorities are implemented. Language models still interpret material and generate reflections, and a small hand-written routine chooses actions for each goal. Source trust also needs a completed feedback path: the inspected caller records confirmations but does not yet send contrary outcomes to the available update function.

What the work has shown

Outcomes now influence the next investigation

The loop rebuilds a payoff estimate from the resolution ledger each tick. Recent fractional improvements can scale a goal type’s priority between 0.5 and 2.0; a four-attempt prior and a nonzero floor keep an initially unproductive kind of investigation available.

The first 120 recorded investigations after a reset were all labeled as having helped because any decrease in deficit counted. Reviewing the actual changes showed a median reduction of 53%, but 13 attempts reduced their deficit by less than 20%, including two below 5%.

The ledger now records fractional change and uses a 20% reporting threshold. Re-reading that history counted 107 of 120 as helped. This corrected the measurement; it did not improve the earlier investigations. Whether the resulting priorities lead to better choices needs a comparison with fixed priorities.

A proof trace exposed errors that confidence missed

An initial graph-deduction test recorded 200 conclusions before external corroboration. Eighty connected mathematical functions to words or nouns through a shared function node; the graph had merged the mathematical concept with a dictionary headword. Other high-confidence conclusions inherited an inverted premise.

Recording the premises made these failures inspectable. It also showed why valid rule application is insufficient when extraction has supplied an ambiguous or reversed relation. This was an initial diagnostic pass, with outcomes still unresolved at the recorded checkpoint.

Artifacts and records

Implementation artifact: Payoff

The payoff mechanism builds a recent, weighted estimate of how much pursuing each kind of goal helped. The prior, decay, and floor are supplied choices. This is implementation evidence, not a performance result.

Inspect the source excerpt
class Payoff:
    """How much each kind of want has been worth lately."""

    def __init__(self, attempts: list | None = None, method: str | None = None) -> None:
        self.by_type: dict[str, float] = {}
        self._build(attempts or [], method)

    @classmethod
    def from_ledger(cls, ledger) -> "Payoff":
        return cls(list(getattr(ledger, "attempts", [])),
                   method=getattr(ledger, "CURRENT_METHOD", None))

    def _build(self, attempts: list, method: str | None) -> None:
        finished: dict[str, list] = {}
        for a in attempts:
            helped = getattr(a, "helped", None)
            if helped is None:
                continue
            # Failures from a way of looking she no longer uses say nothing
            # about the goal -- the same reasoning as fruitless_run.
            if method is not None and getattr(a, "via", None) != method:
                continue
            finished.setdefault(str(getattr(a, "goal_type", "")), []).append(a)

        for kind, group in finished.items():
            weighted = 0.0
            total = 0.0
            # Most recent first, so age is position in the list.
            for age, a in enumerate(reversed(group)):
                w = 0.5 ** (age / HALF_LIFE)
                before = float(getattr(a, "score_before", 0.0) or 0.0)
                after = float(getattr(a, "score_after", 0.0) or 0.0)
                weighted += w * improvement_of(before, after)
                total += w
            if total <= 0:
                continue
            mean = weighted / total
            # Shrunk toward the prior, so a single lucky attempt does not
            # convince her of anything.
            shrunk = ((PRIOR_STRENGTH * PRIOR_IMPROVEMENT + total * mean)
                      / (PRIOR_STRENGTH + total))
            self.by_type[kind] = _multiplier(shrunk)

    def for_type(self, goal_type) -> float:
        """The factor this kind of want has earned. 1.0 when she has no view."""
        kind = getattr(goal_type, "value", goal_type)
        return self.by_type.get(str(kind), 1.0)

    def __bool__(self) -> bool:
        return bool(self.by_type)
Download the verbatim excerpt ↓

What remains open

  • Connect genuine contrary evidence to source trust, keeping disagreement distinct from simple novelty or missing information.
  • Follow recorded predictions through later corroboration, contradiction, or continued absence of evidence.
  • Test whether outcome-sensitive priorities improve investigation choices against a fixed-priority comparison.
  • Make capabilities and their composition discoverable through retained knowledge, while separating acquired behavior from extractor and prompt effects.

Questions this work contributes to