telos — ultimate ends, alignment, non-retreatTELOS.md — the file
A reactive system has an implicit evaluation function: «the user
asked for X → do X well». A proactive system does not: it
generates the intention itself. telos is the component that
decides which intention makes sense before it becomes a proposal
to the user, without asking the user to evaluate everything. In v1.1 it
gains a new telos — cultivate the tools — which does
not concern spontaneous proposals but the silent retreat from a
direct request: a zone the previous design left uncovered.
TELOS.md) with the user's ultimate ends.ActionProposal onto the telos and returns a scalar (expected_alignment).The distinction is not stylistic: it is categorial. Laws and telos inhabit two orthogonal axes of Metnos's life.
| Aspect | Laws (constitution) | Telos (this doc) |
|---|---|---|
| Language | "do not do X" | "approach Y" |
| Mechanism | hard constraint — immediate deny | soft signal — weighted evaluation |
| Owner of the writing | Metnos + user, with rite (Merkle) | user, with a lighter rite (versioned) |
| Precedence | absolute | under Laws, after Policy, before user |
| When it acts | on every action (constitutional preflight) | on spontaneous proposals, and in specific cases (ch. 5) on explicit requests too |
| Cost of violation | hard abort, audit law3_trace_gap | the proposal does not reach the user; or the failure is traced |
TELOS.md — the file
It lives in the workspace as the sixth canonical file (cf.
workspace.html, to be rewritten). Markdown format with a YAML
front-matter. A few lines, hand-written by the user.
---
telos_version: 1.1
written_at: 2026-04-25T12:00:00+02:00
written_by: roberto
previous_hash: <sha256 of the previous version, or "genesis">
signature: <HMAC-SHA256, key separate from the constitutional one>
---
# My ultimate ends
## t.tempo — Free my time from repetitive chores
weight: 0.22
activation_threshold: 0.30
notes: if something frees at least 30 minutes/week and I can trust it,
consider proposing it.
## t.ordine — Keep the order of my digital data
weight: 0.13
activation_threshold: 0.40
notes: I prefer small incremental tidying to large reorganisations.
## t.puntualita — Don't make me miss important deadlines
weight: 0.18
activation_threshold: 0.25
notes: a deadline is "important" if it concerns work, health, family,
or if I marked it explicitly as such.
## t.protezione — Protect the privacy of me and those close to me
weight: 0.18
activation_threshold: 0.20
notes: below this threshold I am paranoid on purpose. Better a false
alarm than a leak.
## t.discrezione — Surprise me usefully but do not interrupt me
weight: 0.09
activation_threshold: 0.50
notes: do not interrupt during meetings, sleep, dinner. Accumulate
and propose at the evening digest.
## t.parsimonia — Don't spend (on APIs, services, compute time) more than needed
weight: 0.08
activation_threshold: 0.35
notes: always pick the cheapest option that reaches the necessary quality.
## t.coltivazione_strumenti — Don't leave a request of mine unmet, if possible
weight: 0.12
activation_threshold: 0.10
notes: if I ask for something your pool cannot yet do, exhaust the
synthesis strategies (compose, generate, ask) before answering
"I cannot". Failure is allowed; silent retreat is not. See
ch. 5 for the stop clause.
| Field | Type | Meaning |
|---|---|---|
id (from the ## heading) | str — t.<slug> | Stable identifier. Used by the TrustStore to track per-telos fitness. |
| Sentence | str — one line | The end in natural form. Read by the LLM for fit estimation. |
weight | float ∈ [0,1] | How much this telos weighs against the others. Sum of weights = 1.0 (renormalised if not). |
activation_threshold | float ∈ [0,1] | The fit on this telos must clear the threshold for the contribution to be counted. Avoids summing noise. |
notes | str — multiline | Context for the LLM: edge cases, judgement criteria, exceptions. Read in the evaluation prompt. |
Where:
gate(fit, threshold) = fit if fit ≥ threshold, else 0. Gate function → a telos contributes nothing if fit is below threshold.urgency ∈ [0.5, 2.0]: 1.0 = no time pressure; 2.0 = deadline within 24h; 0.5 = chronic, no urgency. Multiplicative, not additive.confidence ∈ [0, 1]: how sure Metnos is of its estimate. Proposals based on little data or speculative reasoning → low confidence.bother_cost ∈ [0, ∞): see ch. 6.fiti values are estimated
Not from hardcoded counters. They are estimated by an LLM
with a textual explanation. The estimate is delegated to the Vaglio
— phase 2 (teleological Judge), for a structural reason: an
LLM tends to evaluate its own outputs favourably (self-enhancement bias
documented, Zheng et al. 2023). The Judge of the Vaglio runs on a context
separate from the proposer, prompt separate, possibly provider separate.
The AlignmentEngine of this doc does not produce the
estimate: it composes the final scalar with the fit
values the Vaglio hands it.
expected_alignment in
this doc and the R score in synt
§6 are two distinct metrics:
R ≥ threshold), the teleological Vaglio decides whether it is worth delivering it (expected_alignment ≥ θ). They are orthogonal: an excellent proposal at the wrong moment stays silent.
If expected_alignment < θ, the proposal is
not shown to the user. θ is a parameter of
config.html (to be rewritten) with default 0.15.
Discarded proposals end up in an inspectable internal journal:
// workspace/.audit/telos_rejected.jsonl
{"proposal_id": "ap_...", "kind": "homogenize_filenames",
"expected_alignment": 0.08, "breakdown": {...},
"reason": "bother_cost too high (4 proposals already today)",
"at": "2026-04-25T19:42:00Z"}
The user can inspect this journal to verify Metnos is not suppressing good things («weekly digest: 47 proposals discarded, here are the 5 borderline ones»).
t.coltivazione_strumenti is the newest telos (introduced
on 25 April 2026) and the one that most changes the meaning of
«does not apply to explicit requests». We let it live apart
because mechanically it behaves differently from the others.
Without this telos, the original design had a hole: when a user request the pool could not satisfy, the system could answer «I cannot» without trying alternative strategies. Failure was allowed, but it was a silent retreat: nothing tracked the attempt, nothing grew in the pool, the user lost trust. The right answer is an explicit telos that pushes synt to exhaust the cascade (compose, generate; on longer horizons: merge, generalise) before answering «I cannot».
| Aspect | «Classic» telos | t.coltivazione_strumenti |
|---|---|---|
| Applies to… | only Metnos's spontaneous proposals | also explicit user requests, but only to try strategies, not to judge them |
| What it influences | the expected_alignment of an already-formed proposal | synt's behaviour in forming proposals (the cascade) |
| Cost of violation | the proposal does not reach the user | a request stays unmet without traced attempts |
| Success measured by | high fit + high urgency | cascade exhausted before emitting abandoned |
The telos does not ask for every request to be satisfied; it asks not to retreat in silence. These are two different things.
| Outcome | Form | Honours the telos? |
|---|---|---|
| Success | One strategy of the cascade closes the proto-mnest. | Yes, naturally. |
| Motivated failure | «I tried composing with these N executors, I tried generating with this specification, the birth test failed on case X. I cannot now; I propose Y as a partial alternative.» | Yes: the attempt is traced, the user knows what you knew and what you didn't. |
| Abandonment for budget/policy | «I started the cascade, I consumed the hard budget, I stop. Here is what I have done so far.» | Yes: the limit is documented, it is not a retreat. |
| Silent retreat | «I cannot» without attempts, without explanation. | No. Violates the telos. |
cancelled_by_user (not abandoned:
there is a difference), and the pattern is not retried automatically.
Without the stop clause, the telos would be paternalism: «you asked me X, I keep looking even though you no longer want it». The stop makes non-retreat courage, not stubbornness (in the words of the synt microdesign). The stop is always audible: the LLM handling the turn carries in its prompt an explicit recogniser for stop phrases.
The non-retreat telos does not mean unlimited retry. The abandonment thresholds remain valid and are fixed in synt (ch. 8.3):
Once the cascade is exhausted within these thresholds, failure is allowed. The non-retreat telos does not ask to exceed them: it asks not to stop before.
The user has a finite capacity to evaluate proposals. The more arrive in
a window, the less attention each gets. For this reason, the alignment
function includes a bother_cost that grows with the recent
frequency of published proposals. The novelty in v1.1 is the separation
between ad-hoc proposals and scheduler-driven invocations
(the builtin described in executor.html
ch. 10).
Where k(Δt) is a decreasing exponential kernel: a
proposal published 1 minute ago contributes a lot, one of 8 hours ago
almost nothing.
When a proposal is accepted together with a cadence (e.g. «ok,
do this summary every morning at 8»), the consent covers the
entire cadence, not only the first execution. From that moment on the
subsequent invocations are not new spontaneous proposals: they are
firings of the scheduler
builtin, already pre-approved. The ad-hoc bother budget does not apply.
| Type of publication | Counts toward bother budget? | Modulation |
|---|---|---|
| Spontaneous ad-hoc proposal | Yes, full | Base model above. Telegram immediate ≤ 3/day, ≤ 1/hour. |
| Scheduler firing in agreed cadence | No, separate quota | One attention spend per scheduled firing. If it falls in a protected window, it is deferred to the next non-protected slot. |
| Scheduler firing outside the agreed cadence | Yes, partial (50%) | If the schedule fires at an atypical time (e.g. recent change of cadence, exceptional event), it weighs half an ad-hoc proposal. |
| Response to an explicit request | No | The user is already waiting. No bother. |
| Channel | Default ad-hoc | Default scheduler |
|---|---|---|
| Evening digest | up to 10 grouped proposals | included (1 digest, unlimited) |
| Telegram (immediate) | max 3/day, max 1/hour | active schedules ≤ 2/day per channel |
| Interactive CLI | max 2/session | scheduling on-demand |
| Protected windows | 0 | 0 (defer to next non-protected slot) |
Three kinds of feedback update the effective weights of the
telos — not the declared weights in TELOS.md, which
remain the user-revisable ground truth. The TrustStore
defined in rl_offline.html (to be rewritten) extends with
an axis telos_fitness: dict[telos_id, EMA].
| Signal | Strength | Effect on linked telos |
|---|---|---|
| Explicit accept | +1.0 | EMA rises. Effective weight grows moderately. |
| Accept with edit | +0.5 | EMA rises a little. Signals the telos was right, the plan was not. |
| Explicit reject | −1.0 | EMA falls. The telos is less important than declared. |
| Reject with «never again» | −2.0 | EMA falls a lot. The effect_class enters the telos's never-list. |
| Explicit stop (ch. 5.4) | −0.7 | EMA of t.coltivazione_strumenti alone falls: the user has reduced the appetite to insist on that thread. |
| 48h silence | −0.3 | Weak but present signal. |
| Viewed but undecided | −0.1 | Almost no effect. |
The effective weight oscillates between 50% and 150% of the declared one. It never goes to zero (to avoid catastrophic forgetting of a telos), it never doubles (to respect the user's intent).
This is the trickiest trap of the design. A telos system applied without discernment becomes paternalistic. Without the distinction below, the non-retreat telos of ch. 5 would be the most extreme manifestation of this risk.
Operationally, the alignment function never applies to:
It applies to:
ActionProposals generated by reflection, ager, mnestome.
This clause must also be reflected in constitution.html (to
be rewritten) as a sub-law: the Constitution is the level that prevents
edge cases (e.g. synthesis attempts that would require forbidden
capabilities).
The user's stop is not only «leave it». The LLM pipeline carries in its prompt a recogniser for equivalent phrases, in Italian and English:
Ambiguous stops (e.g. «hmm, let's see later») trigger an explicit confirmation: «do you want me to stop on attempt X?». Better one extra question than insisting on an unwanted attempt.
from typing import Protocol, Literal
from dataclasses import dataclass
from datetime import datetime
from uuid import UUID
@dataclass(frozen=True)
class Telos:
id: str # "t.coltivazione_strumenti"
phrase: str # "Don't leave a request of mine unmet, if possible"
weight_declared: float # [0,1], normalised sum
activation_threshold: float # [0,1]
notes: str # context for the LLM
is_non_retreat: bool = False # only t.coltivazione_strumenti
@dataclass(frozen=True)
class FitEstimate:
telos_id: str
fit: float # [0,1]
why: str # textual explanation (for audit)
@dataclass(frozen=True)
class AlignmentResult:
proposal_id: UUID
expected_alignment: float
per_telos: list[FitEstimate]
urgency: float
confidence: float
bother_cost: float
decision: Literal["publish", "reject", "defer_to_digest"]
threshold_used: float
at: datetime
@dataclass(frozen=True)
class StopSignal:
"""Emitted when the user activates the stop clause."""
request_id: str # synt request_id to stop
target_intent: str # what to stop
raw_phrase: str # exact user words (audit)
at: datetime
class TelosStore(Protocol):
"""Reads TELOS.md and exposes the current telos."""
def current(self) -> list[Telos]: ...
def get(self, telos_id: str) -> Telos | None: ...
def version(self) -> str: ... # current hash
class AlignmentEngine(Protocol):
async def evaluate(
self,
proposal: "ActionProposal",
urgency_hint: float = 1.0,
) -> AlignmentResult:
"""Estimate fit per telos (Vaglio), compose expected_alignment,
apply bother_cost, decide publish/reject/defer."""
...
class BotherBudget(Protocol):
def current_cost_adhoc(self, channel: str, at: datetime) -> float: ...
def scheduler_quota_left(self, channel: str, schedule_id: str) -> int: ...
def record_published_adhoc(self, channel: str, proposal_id: UUID) -> None: ...
def record_scheduler_firing(self, channel: str, schedule_id: str) -> None: ...
def in_protected_window(self, at: datetime) -> bool: ...
class StopRecognizer(Protocol):
"""Recognises the stop clause in the user's words."""
async def detect(self, user_text: str, current_intent: str | None) -> StopSignal | None:
"""Returns a StopSignal if the phrase is a clear stop;
None if it is not; raises a confirmation if ambiguous."""
...
class TelosFeedback(Protocol):
"""Updates per-telos EMAs from user signals."""
async def on_accept(self, proposal_id: UUID) -> None: ...
async def on_accept_with_edit(self, proposal_id: UUID) -> None: ...
async def on_reject(self, proposal_id: UUID, never_again: bool) -> None: ...
async def on_stop(self, signal: StopSignal) -> None: ...
async def on_silence_48h(self, proposal_id: UUID) -> None: ...
async def on_viewed_undecided(self, proposal_id: UUID) -> None: ...
# Errors
class TelosFileMalformed(Exception): ...
class TelosSignatureInvalid(Exception): ...
class TelosFitEstimationFailed(Exception): ...
class StopAmbiguousNeedsConfirm(Exception): ...
TELOS.md is not technically constitutional (the Laws are) but still deserves a light rite:
previous_hash of the previous one; the old one moves to .audit/telos/. Light Merkle.| Alternative | Outcome | Reason |
|---|---|---|
| No explicit TELOS, only implicit feedback | discarded | Cold start impossible: without declared telos, the first 50 proposals are random. The user rejects them all, the EMA collapses, the system goes silent. |
| Non-retreat telos as Law 4 of the Constitution | discarded (25/4/2026) | Breaks the grammar of Laws (negative prohibitions). The telos is a positive push, it belongs here. See Architecture ch. 11. |
| Reward function learned from a dataset | discarded | We have no dataset. A learned function is opaque: the user does not know what Metnos is optimising. |
| Hierarchical goal graph | postponed | Nested telos increase expressive power but break manual writability. 3-7 flat telos cover 90% of cases. |
| Single global threshold θ (no per-telos) | partial | Adopted as the final θ, but combined with per-telos thresholds (activation_threshold) to prevent low noise across many telos from summing up. |
| Online learning (continuous RL) | discarded | Risk of reward hacking, opaque to the user. EMA from explicit signals is enough. |
| Implicit stop (timeout) | discarded | The user might be distracted, not uninterested. Stop must be explicit or confirmed. |
| Case | Verification |
|---|---|
| Missing TELOS.md | The alignment function rejects every spontaneous proposal with reason="no_telos_declared". Metnos asks the user to fill the file. |
| Telos with non-normalised weights | Sum renormalised to 1.0 at load. Warning in log. Not an error. |
| fit = 0 on all telos | expected_alignment ≤ 0 − bother_cost < θ: reject. |
| High fit only on a sub-threshold telos | The contribution is set to 0 by the gate. Reject unless another telos contributes. |
| Proposal close to a protected window | Defer to evening digest, not immediate publication. |
| Same proposal type rejected 3 times with «never again» | The effect_class enters telos_neverlist: subsequent ones are auto-rejected without an LLM call. |
| Explicit user request that violates a «classic» telos (e.g. high spend with parsimony telos) | The alignment function is not invoked. Anti-paternalism (ch. 8). |
| Request the pool cannot serve | synt enters the cascade. The non-retreat telos is active. If the cascade fails, outcome is abandoned motivated (not cancelled). |
| User activates the stop clause mid-cascade | State moves to cancelled_by_user. EMA of t.coltivazione_strumenti drops by 0.7. The pattern is not retried within 24h. |
| Ambiguous stop («hmm let's see») | Metnos asks for confirmation: «do you want me to stop on X?». Does not interrupt on its own. |
| Scheduler firing in protected window | Deferred to next non-protected slot. Not published immediately, not discarded. |
| Scheduler firing outside the agreed cadence (exceptional event) | Weighs 50% of an ad-hoc proposal's bother. |
| TELOS.md revision with a removed telos | The new file valid, the old one in .audit/telos/. The removed telos's EMA is discarded. Audit record with diff. |
| 10 ad-hoc proposals in 1 hour via Telegram | Bother_cost grows exponentially; from the 4th on, reject (defer_to_digest) even with high expected_alignment. |
| R vs expected_alignment disambiguation | A synt proposal with R = 0.85 but expected_alignment = 0.10 is not published: quality is not enough, the moment is wrong. |
t.coltivazione_strumenti). Will another ever be needed? For example, «don't leave a security warning unaddressed»? Open.t.coltivazione_strumenti below the activation threshold and effectively disable the telos? Or stick to per-occurrence rejection? Open; conservative default: per-occurrence rejection.telos_neverlist mechanism today operates on the effect_class; possible future extension: link an effect_class to several telos at once. Open.
Metnos — telos microdesign v1.1 — 2026-04-25
Rewrite. Replaces telos v1.0 (myclaw, neurons, synapses). Without telos, proactivity is noise.