# Osysharp.Privacy — what the app holds about a person, and what their request does to it

> `Osysharp.Privacy` answers a person who asks what an app holds about them, asks for a copy, or asks to be erased. Each kit that holds personal data says what it holds and for how long; a request becomes a plan, and the answer tells the person what was erased, what was kept, on what basis and until when.

<!-- id: agent-kit-privacy · area: agent · stability: preview · html: https://osysharp.com/reference/agent/kit-privacy/ -->

> **You are here:** [Building with agents](https://osysharp.com/reference/agent/guide/) › [The kits](https://osysharp.com/reference/agent/guide-kits/) › Privacy

## Summary        {#summary}
`Osysharp.Privacy` answers a person who asks what an app holds about them, asks for a copy, or asks to be erased. Each kit that holds personal data says what it holds and for how long; a request becomes a plan, and the answer tells the person what was erased, what was kept, on what basis and until when.

It is not an agents kit. The four bridges beside it make the agents family part of the same request: one erasure reaches a case, the agent's record of the work it did on it, and what that work found.

|  |  |
|---|---|
| Package | `Osysharp.Privacy`, version 0.11.0 |
| You add it with | `use Osysharp.Privacy;` in the app's manifest. |
| It sits on | [[agent-kit-work-queues\|WorkQueues]] |
| It also uses | `Identity`, `Mail`, `Storage`, `Ui`, `Workflow` — parts of the platform's own library |
| Bridges that arrive when it meets another kit | [[agent-kit-privacy-agents\|Privacy.Agents]], [[agent-kit-privacy-agents-human-requests\|Privacy.Agents.HumanRequests]], [[agent-kit-privacy-assignments\|Privacy.Assignments]], [[agent-kit-privacy-human-requests\|Privacy.HumanRequests]], [[agent-kit-privacy-llm\|Privacy.Llm]], [[agent-kit-privacy-work-repositories\|Privacy.WorkRepositories]] |
| Its own test app | The smallest correct consumer — `kits/privacy/tests` |

## Description    {#description}

### What do you get without writing anything?   {#free}
- The person's own page: see what is held, ask for a copy, ask to be erased.
- A daily purge of what has outlived its period — for everybody, not only for people who asked.
- Legal holds: what is under one is kept until it is lifted.
- Retention periods the tenant can read and change.

### When do you need it?   {#when}
When the app holds personal data. See [[agent-guide-choosing#privacy]].

### What does it expose?   {#exposes}
The tables below are generated from the kit itself, not written by hand: `osy kits Osysharp.Privacy --surface` lists each of
them with the code of the kit's own test app that uses it, and the tests that show it working.

**Settings** — one line in the app, each field with a default.

| You write | It says |
|---|---|
| `app.Privacy = new PrivacySetup { Controller, FiscalYearEndMonth, FiscalYearEndDay, SupervisoryAuthority, ReviewPlans, HoldLiftNeedsSecondPerson, Mails }` | The app's privacy setup. |

**Contracts you can implement** — a class of yours that the kit then calls.

| Contract | What it is |
|---|---|
| `interface IPersonalDataHolder { Key, Categories, Count, BlockedBy, KeptWith, Erase, Restrict, Export, Purge, Hold, Declared }` | Something that holds personal data. |
| `interface ISubjectLinks { Under }` | Something that knows which rows hang under another: the work attached to an assignment, the items in its repository, the work a piece of work handed on. |
| `interface IRequesterProof { Key, Start, Prove, Spend, ProvenAddress }` | Proving the signed-in person, now — implemented by the sign-in kit (`Osysharp.Privacy.UserAccounts` for `Osysharp.UserAccounts`), discovered. |
| `interface IAddressProof { Key, StartFor, Prove, SpendForVisit }` | Proving an address, for a person with no account — implemented by the kit that holds people by their address (`Osysharp.Privacy.Conversations`, a code mailed through the desk's own mail channel), D… |

**Policies you answer** — each is a question the kit asks your app: `policy Name => …;`

| Policy | The question | Until the app says otherwise |
|---|---|---|
| `PlacesLegalHolds` | Who may place and lift legal holds — the app's to say: `policy PlacesLegalHolds => IsAdmin;`. | nothing: the app must answer it |
| `ManagesPrivacy` | Who manages privacy: files and approves requests, and sets the periods. | nothing: the app must answer it |

**Functions you call**, those its own tests show most first.

| Function | What it does | Tests that show it |
|---|---|---|
| `Holders()` | Every holder of personal data in the app — the app's own and every kit's, discovered (never wired), in a stable order. | 53 |
| `RetentionOf(DataCategory category)` | The period that applies to `category` now. | 52 |
| `AllCategories()` | Every category every holder declares. | 49 |
| `HoldLiftNeedsSecondPerson()` | Whether a lift needs a second person — the app's setting (an organisation's policy may set it). | 46 |
| `CategoryOf(string key)` | The category declared under `key` — refused, naming the keys there are, when none is. | 40 |
| `StatutoryDue(DateTime receivedAt)` | The statutory deadline for a request received at `receivedAt`: the same date one calendar month later (the month's last day when there is no such date — `AddMonths` already says so), moved to the f… | 36 |
| `IsHeld(DataSubject subject)` | Whether a hold in force covers the person `subject`. | 32 |
| `DeclarationProblems()` | What is wrong with the declarations, one sentence each — empty when nothing is. | 30 |
| `HeldSentence()` | The sentence a person reads for what a hold keeps — the basis, never the matter. | 30 |
| `KeptThrough(DateTime until)` | The last day a row whose period ends at `until` (exclusive) is kept — what a response says. | 30 |
| `ReadablePathOf(string path)` | Where the readable copy of the export at `path` is: beside it, as `your-data.html`. | 27 |
| `FileRequest(RequestKind right, Guid? account, string email, IdentityCheck check, string checkedHow, string phone = …)` | File a request on a person's behalf (a letter, a call) — saying HOW you checked it is them. | 27 |
| `ApproveRequest(PrivacyRequest r)` | Approve a planned request — it runs now. | 27 |
| `PlaceHold(string email, Guid? account, string matter, string reason, DateTime reviewBy)` | Place a hold on a person — every category about them — until it is lifted. | 18 |
| `RecheckWaiting()` | Ask every request waiting on a block again — what the daily purge does, and what an app calls when a block clears (an order delivered). | 12 |
| `ProveItIsMe()` | Start proving it is you. | 11 |
| `ConfirmItIsMe(Guid proof, string code)` | The code from that mail. | 11 |
| `AskAboutMe(RequestKind right, Guid proof)` | Ask for yourself: a copy of your data, your data to take elsewhere, erasure, or restriction — with the proof you just made. | 11 |
| `LiftHold(LegalHold hold, string reason)` | Lift a hold, saying why. | 10 |
| `KeepUntil(DataCategory category, DateTime itemDate)` | The first instant after a row of `category` dated `itemDate` stops being kept — it is kept through the whole of the day before (`KeptThrough`). | 9 |
| `RetentionRows()` | Every category every holder declares, as the retention page shows it — the ones waiting for confirmation first. | 7 |
| `MarkAbout(Guid row, string kind, DataSubject subject)` | Say whose data a row is: the row `row`, of the kind `kind`, is about `subject` — their account, each address and each number given. | 6 |
| `PurgeNow()` | Purge what reached the end of its period, now — what the daily run does, run by the kit's own run as the system (`ManualPurge`), and recorded with who asked. | 6 |
| `ConfirmHoldLift(LegalHold hold)` | Confirm somebody else's lift — the second person. | 5 |
| `ReviewHold(LegalHold hold, DateTime next)` | Reviewed: the hold stays, and is looked at again on `next`. | 5 |
| `RowsAbout(DataSubject subject, string kind)` | The rows of one kind that are about a person: the ones marked about them — by the account or by any address or number the request proved — and everything that hangs under a row marked about them,… | 5 |
| `MyRequests()` | The signed-in person's own requests, newest first. | 5 |
| `SetRetention(string categoryKey, int months, RetentionStart from, string basisDetail = …, string jurisdiction = …, string reason = …)` | Set how long `categoryKey` is kept, from when, and in whose words. | 5 |
| `PlaceCaseHold(string entity, Guid row, string label, string matter, string reason, DateTime reviewBy)` | Place a hold on one case — the row `row` of `entity`, as people read it `label` ("Order 1042") — until it is lifted. | 4 |
| `ExtendRequest(PrivacyRequest r, int months, string reason)` | Extend a request's deadline by up to two further months (Art. | 4 |
| `FetchMyExport(PrivacyRequest request)` | Fetch your export — once, within its days: answers its two files' links, which work for a few minutes. | 4 |
| `ExportOf(PrivacyRequest r)` | The export of request `r`, as written — for the people managing privacy to check before it goes. | 3 |
| `RecordsOfProcessing()` | The records of processing: one row per category, from the declarations and the settings. | 3 |
| `RetryRequest(PrivacyRequest r)` | Run a failed request's plan again — after what failed was fixed. | 3 |
| `ExportReady(PrivacyRequest r)` | Whether request `r`'s export can still be fetched by its person. | 3 |
| `WhatWeKeepAboutMe()` | What the app keeps about people, and how much of each it holds about the signed-in person right now — a count per category from its holder (`Count`, the same a request's plan asks), never what the … | 3 |
| `WhatAskingDoes(RequestKind right)` | What a request would do, category by category, before it is made — "we will erase…, we will keep… until…". | 3 |
| `ApplyPreset(string jurisdiction)` | Apply a jurisdiction's bookkeeping preset to every bookkeeping category — one action, recorded, never automatic. | 2 |
| `IsCaseHeld(Guid row)` | Whether a hold in force covers the case `row` — what a holder asks before it erases or purges that row. | 1 |
| `IsMarkedHeld(Guid row, string kind)` | Whether a legal hold in force covers anybody the row `row` was marked about — what a holder asks before it purges a marked row at the end of its period. | 1 |
| `CanAskWithoutAnAccount()` | Whether a person with no account can ask here — something proves their address. | 1 |
| `ProveAnAddress(string address)` | Start proving an address, with no account: a code goes there. | 1 |
| `ConfirmAnAddress(Guid proof, string code)` | The code from that mail. | 1 |
| `AskAboutAnAddress(RequestKind right, Guid proof)` | Ask about the address you just proved, with no account: a copy, your data to take elsewhere, erasure, or restriction. | 1 |
| `WhatWeKeep()` | What the app keeps about people, and why — from the same declarations as the records of processing, never typed. | 1 |
| `SubjectOfHold(LegalHold hold)` | The person a hold is on, as a request would name them. | 0 |

**Screens and components you mount** — each is one line in a page of yours.

| Component | What it draws |
|---|---|
| `ControllerEditor()` | The controller's legal name — named here, saved with the bar. |
| `HoldReviewPane(item)` | A hold due for review, opened from the Inbox: what is held and why, who placed it and when — and the two ways to settle it: keep it (with the next review date) or lift it (with a reason, confirmed by a second person when the app requires one). |
| `HoldControl(entity, row, label, opened)` | Place a legal hold on a case from the record's own page — an order, a conversation, a candidacy: `entity` is what kind of record it is ("Conversation"), `row` the record, `label` how people read it ("Ticket #1042"). |
| `LegalHoldsEditor()` | The legal holds page: what is held and why, placing a hold on a person, lifting one with a reason (confirmed by a second person when the app requires it), and keeping one past its review date. |
| `MyPrivacy()` | The person's privacy page: what is kept about people and why, asking (proven first, with what it will do shown before it is sent), and their requests. |
| `ExportSaved(links)` | What a person reads once their export is fetched: the readable copy is on its way, and the data file is one more link — both for a few minutes. |
| `AskChoice(title, body, onPress, picked)` | One way to ask — a choice card. |
| `AskWithoutAnAccount()` | Asking about your data without an account — a customer who only ever wrote to the desk by mail. |
| `ExportByLinkPage(link)` | The page an export link opens — a person with no account downloads their data once. |
| `PrivacyRequestPane(request)` | A privacy request, as the people managing privacy work it on the Inbox: the deadline, how identity was checked, the plan line by line — approve it, keep a legitimate-interest line on written grounds, extend the deadline with its reason, run it again after a failure — and what the person is told. |
| `RetentionEditor()` | The retention page: each category's period (change it within the kit's limits — or outside them, saying the jurisdiction and why — or confirm one only the tenant can decide), a jurisdiction's bookkeeping preset, and how plans are reviewed. |

**Pages it brings** — routes the kit serves by itself.

| Route | Page |
|---|---|
| `/settings/privacy/controller` | `ControllerSettings` |
| `/settings/privacy/holds` | `LegalHoldsSettings` |
| `/privacy` | `MyPrivacyPage` |
| `/privacy/ask` | `AskWithoutAnAccountPage` |
| `/privacy/export/{link}` | `ExportByLinkPage`: The page an export link opens — a person with no account downloads their data once. |
| `/settings/privacy` | `PrivacySettings` |

**Records your app grants access to** — the kit writes them; `partial entity X { security { … } }` says who else reads them.

| Record | What it is |
|---|---|
| `SubjectMark` | One row is about one person — by their account, or by the fingerprint of an address or a number of theirs. |

## What to read next   {#read-next}
- [Osysharp.Privacy.Agents — what agents did for a person and about a person, under that person's request](https://osysharp.com/reference/agent/kit-privacy-agents/) — what agents did for a person and about a person, under that person's request
- [Choosing — I want X, so use Y, not Z, because](https://osysharp.com/reference/agent/guide-choosing/) — choosing — I want X, so use Y, not Z, because
- [What stays under people's control — ten promises, and where each is shown](https://osysharp.com/reference/agent/overview-control/) — what stays under people's control — ten promises, and where each is shown

## Go deeper   {#see-also}
- [The Privacy kit — erasure that keeps only what the company must or may](https://osysharp.com/reference/security/privacy-kit/) — the kit: holders, requests, plans, periods
- [personal data (Classification(Personal.X))](https://osysharp.com/reference/security/personal-data/) — personal data
- [Legal holds — nothing a dispute needs is erased or purged while it lasts](https://osysharp.com/reference/security/legal-holds/) — legal holds
- [Privacy for the agent family — agents, the model meter, assignments and work repositories under a person's request](https://osysharp.com/reference/agent/privacy/) — the agents family under a person's request
