summaryrefslogtreecommitdiff
path: root/www/fileformat.wiki
diff options
context:
space:
mode:
authorcashmere <cashmere@autistici.org>2026-09-04 09:05:24 +0200
committercashmere <cashmere@autistici.org>2026-09-04 09:05:24 +0200
commit4f49b16079b27d7ce633619e4cddfdf2bffbc952 (patch)
treec296c1e7f3c3e2f6859c6d3a1b1b208779b89679 /www/fileformat.wiki
downloadrelic-master.tar.gz
initial commitHEADmaster
Diffstat (limited to 'www/fileformat.wiki')
-rw-r--r--www/fileformat.wiki995
1 files changed, 995 insertions, 0 deletions
diff --git a/www/fileformat.wiki b/www/fileformat.wiki
new file mode 100644
index 0000000..3eaa3cc
--- /dev/null
+++ b/www/fileformat.wiki
@@ -0,0 +1,995 @@
+<title>Fossil File Formats</title>
+
+The global state of a fossil repository is kept simple so that it can
+endure in useful form for decades or centuries.
+A fossil repository is intended to be readable,
+searchable, and extensible by people not yet born.
+
+The global state of a fossil repository is an unordered
+set of <i>artifacts</i>.
+An artifact might be a source code file, the text of a wiki page,
+part of a trouble ticket, a description of a check-in including all
+the files in that check-in with the check-in comment and so forth.
+Artifacts are broadly grouped into two types: content artifacts and
+structural artifacts. Content artifacts are the raw project source-code
+files that are checked into the repository. Structural artifacts have
+special formatting rules and are used to show the relationships between
+other artifacts in the repository. It is possible for an artifact to
+be both a structure artifact and a content artifact, though this is
+rare. Artifacts can be text or binary.
+
+In addition to the global state,
+each fossil repository also contains local state.
+The local state consists of web-page formatting
+preferences, authorized users, ticket display and reporting formats,
+and so forth. The global state is shared in common among all
+repositories for the same project, whereas the local state is often
+different in separate repositories.
+The local state is not versioned and is not synchronized
+with the global state.
+The local state is not composed of artifacts and is not intended to be enduring.
+This document is concerned with global state only. Local state is only
+mentioned here in order to distinguish it from global state.
+
+<h2 id="names">1.0 Artifact Names</h2>
+
+Each artifact in the repository is named by a hash of its content.
+No prefixes, suffixes, or other information is added to an artifact before
+the hash is computed. The artifact name is just the (lower-case
+hexadecimal) hash of the raw artifact.
+
+Fossil currently computes artifact names using either SHA1 or SHA3-256. It
+is relatively easy to add new algorithms in the future, but there are no
+plans to do so at this time.
+
+When referring to artifacts in using tty commands or webpage URLs, it is
+sufficient to specify a unique prefix for the artifact name. If the input
+prefix is not unique, Fossil will show an error. Within a structural
+artifact, however, all references to other artifacts must be the complete
+hash.
+
+Prior to Fossil version 2.0, all names were formed from the SHA1 hash of
+the artifact. The key innovation in Fossil 2.0 was adding support for
+alternative hash algorithms.
+
+<h2 id="structural">2.0 Structural Artifacts</h2>
+
+A structural artifact is an artifact with a particular format
+that is used to define the relationships between other artifacts in the
+repository.
+Fossil recognizes the following kinds of structural
+artifacts:
+
+<ul>
+<li> [#manifest | Manifests] </li>
+<li> [#cluster | Clusters] </li>
+<li> [#ctrl | Control (a.k.a. Tag) Artifacts] </li>
+<li> [#wikichng | Wiki Pages] </li>
+<li> [#tktchng | Ticket Changes] </li>
+<li> [#attachment | Attachments] </li>
+<li> [#event | TechNotes] </li>
+<li> [#forum | Forum Posts] </li>
+</ul>
+
+These eight structural artifact types are described in subsections below.
+
+Structural artifacts are UTF-8 text. The artifact may be PGP clearsigned.
+After removal of the PGP clearsign header and suffix (if any) a structural
+artifact consists of one or more "cards" separated by a single newline
+(ASCII: 0x0a) character. Each card begins with a single
+character "card type". Zero or more arguments may follow
+the card type. All arguments are separated from each other
+and from the card-type character by a single space
+character. There is no surplus white space between arguments
+and no leading or trailing whitespace except for the newline
+character that acts as the card separator. All cards must be in strict
+lexicographical order (except for an
+[./fileformat.wiki#outofordercards|historical bug compatibility]).
+There may not be any duplicate cards.
+
+In the current implementation (as of 2017-02-27) the artifacts that
+make up a fossil repository are stored as delta- and zlib-compressed
+blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This
+is an implementation detail and might change in a future release. For
+the purpose of this article "file format" means the format of the artifacts,
+not how the artifacts are stored on disk. It is the artifact format that
+is intended to be enduring. The specifics of how artifacts are stored on
+disk, though stable, is not intended to live as long as the
+artifact format.
+
+<h3 id="manifest">2.1 The Manifest</h3>
+
+A manifest defines a check-in.
+A manifest contains a list of artifacts for
+each file in the project and the corresponding filenames, as
+well as information such as parent check-ins, the username of the
+programmer who created the check-in, the date and time when
+the check-in was created, and any check-in comments associated
+with the check-in.
+
+Allowed cards in the manifest are as follows:
+
+<div class="indent">
+<b>B</b> <i>baseline-manifest</i><br>
+<b>C</b> <i>checkin-comment</i><br>
+<b>D</b> <i>time-and-date-stamp</i><br>
+<b>F</b> <i>filename</i> ?<i>hash</i>? ?<i>permissions</i>? ?<i>old-name</i>?<br>
+<b>N</b> <i>mimetype</i><br>
+<b>P</b> <i>artifact-hash</i>+<br>
+<b>Q</b> (<b>+</b>|<b>-</b>)<i>artifact-hash</i> ?<i>artifact-hash</i>?<br>
+<b>R</b> <i>repository-checksum</i><br>
+<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <b>*</b> ?<i>value</i>?<br>
+<b>U</b> <i>user-login</i><br>
+<b>Z</b> <i>manifest-checksum</i>
+</div>
+
+A manifest may optionally have a single <b>B</b> card. The <b>B</b> card specifies
+another manifest that serves as the "baseline" for this manifest. A
+manifest that has a <b>B</b> card is called a delta-manifest and a manifest
+that omits the <b>B</b> card is a baseline-manifest. The other manifest
+identified by the argument of the <b>B</b> card must be a baseline-manifest.
+A baseline-manifest records the complete contents of a check-in.
+A delta-manifest records only changes from its baseline.
+
+A manifest must have exactly one <b>C</b> card. The sole argument to
+the <b>C</b> card is a check-in comment that describes the check-in that
+the manifest defines. The check-in comment is text. The following
+escape sequences are applied to the text:
+A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73). A
+newline (ASCII 0x0a) is "\n" (ASCII 0x5C, x6E). A backslash
+(ASCII 0x5C) is represented as two backslashes "\\". Apart from
+space and newline, no other whitespace characters are allowed in
+the check-in comment. Nor are any unprintable characters allowed
+in the comment.
+
+A manifest must have exactly one <b>D</b> card. The sole argument to
+the <b>D</b> card is a date-time stamp in the ISO8601 format. The
+date and time should be in coordinated universal time (UTC).
+The format one of:
+
+<pre class="indent"><i>YYYY-MM-DD<b>T</b>HH:MM:SS
+YYYY-MM-DD<b>T</b>HH:MM:SS.SSS</i></pre>
+
+A manifest has zero or more <b>F</b> cards. Each <b>F</b> card identifies a file
+that is part of the check-in. There are one, two, three, or four
+arguments. The first argument is the pathname of the file in the
+check-in relative to the root of the project file hierarchy. No ".."
+or "." directories are allowed within the filename. Space characters
+are escaped as in <b>C</b> card comment text. Backslash characters and
+newlines are not allowed within filenames. The directory separator
+character is a forward slash (ASCII 0x2F). The second argument to the
+<b>F</b> card is the lower-case hexadecimal artifact hash of
+the content artifact. The second argument is required for baseline
+manifests but is optional for delta manifests. When the second
+argument to the <b>F</b> card is omitted, it means that the file has been
+deleted relative to the baseline (files removed in baseline manifests
+versions are <em>not</em> added as <b>F</b> cards). The optional 3rd argument
+defines any special access permissions associated with the file. This
+can be defined as "x" to mean that the file is executable or "l"
+(small letter ell) to mean a symlink. All files are always readable
+and writable. This can be expressed by "w" permission if desired but
+is optional. The file format might be extended with new permission
+letters in the future. The optional 4th argument is the name of the
+same file as it existed in the parent check-in. If the name of the
+file is unchanged from its parent, then the 4th argument is omitted.
+
+Sidebar: due to a minor bug in Fossil's early history (specifically
+2008-08-11 to 2009-01-20), manifest parsers must be able to tolerate a
+single space character after the UUID value even if no permissions
+value is set. Normally the space would indicate that another token
+is expected, but this one case requires leniency to allow
+[/artifact/32b480faa3465591|a single known historical artifact] to parse.
+For full details see
+[https://claude.ai/code/artifact/c121be7a-5c6a-4a18-ab7f-63d086ac8071|this article].
+
+A manifest has zero or one <b>N</b> cards. The <b>N</b> card specifies the mimetype for the
+text in the comment of the <b>C</b> card. If the <b>N</b> card is omitted, a default mimetype
+is used. Note that the <b>N</b> card has never actually been used by
+any Fossil implementation. The implementation has always interpreted
+check-in comments according to the [/wiki_rules|Fossil Wiki formatting rules].
+There are no current plans to ever change that.
+
+A manifest has zero or one <b>P</b> cards. Most manifests have one <b>P</b> card.
+The <b>P</b> card has a varying number of arguments that
+define other manifests from which the current manifest
+is derived. Each argument is a lowercase
+hexadecimal artifact hash of a predecessor manifest. All arguments
+to the <b>P</b> card must be unique within that card.
+The first argument is the artifact hash of the direct ancestor of the manifest.
+Other arguments define manifests with which the first was
+merged to yield the current manifest. Most manifests have
+a <b>P</b> card with a single argument. The first manifest in the
+project has no ancestors and thus has no <b>P</b> card or (depending
+on the Fossil version) an empty <b>P</b> card (no arguments).
+
+A manifest has zero or more <b>Q</b> cards. A <b>Q</b> card is similar to a <b>P</b> card
+in that it defines a predecessor to the current check-in. But
+whereas a <b>P</b> card defines the immediate ancestor or a merge
+ancestor, the <b>Q</b> card is used to identify a single check-in or a small
+range of check-ins which were cherry-picked for inclusion in or
+exclusion from the current manifest. The first argument of
+the <b>Q</b> card is the artifact ID of another manifest (the "target")
+which has had its changes included or excluded in the current manifest.
+The target is preceded by "+" or "-" to show inclusion or
+exclusion, respectively. The optional second argument to the
+<b>Q</b> card is another manifest artifact ID which is the "baseline"
+for the cherry-pick. If omitted, the baseline is the primary
+parent of the target. The
+changes included or excluded consist of all changes moving from
+the baseline to the target.
+
+The <b>Q</b> card was added to the interface specification on 2011-02-26.
+Older versions of Fossil will reject manifests that contain <b>Q</b> cards.
+
+A manifest may optionally have a single <b>R</b> card. The <b>R</b> card has
+a single argument which is the MD5 checksum of all files in
+the check-in except the manifest itself. The checksum is expressed
+as 32 characters of lowercase hexadecimal. The checksum is
+computed as follows: For each file in the check-in (except for
+the manifest itself) in strict sorted lexicographical order,
+take the pathname of the file relative to the root of the
+repository, append a single space (ASCII 0x20), the
+size of the file in ASCII decimal, a single newline
+character (ASCII 0x0A), and the complete text of the file.
+Compute the MD5 checksum of the result.
+
+A manifest might contain one or more <b>T</b> cards used to set
+[./branching.wiki#tags | tags or properties]
+on the check-in. The format of the <b>T</b> card is the same as
+described in <i>Control Artifacts</i> section below, except that the
+second argument is the single character "<b>*</b>" instead of an
+artifact ID. The <b>*</b> in place of the artifact ID indicates that
+the tag or property applies to the current artifact. It is not
+possible to encode the current artifact ID as part of an artifact,
+since the act of inserting the artifact ID would change the artifact ID,
+hence a <b>*</b> is used to represent "self". <b>T</b> cards are typically
+added to manifests in order to set the <b>branch</b> property and a
+symbolic name when the check-in is intended to start a new branch.
+
+Each manifest has a single <b>U</b> card. The argument to the <b>U</b> card is
+the login of the user who created the manifest. The login name
+is encoded using the same character escapes as is used for the
+check-in comment argument to the <b>C</b> card.
+
+A manifest must have a single <b>Z</b> card as its last line. The argument
+to the <b>Z</b> card is a 32-character lowercase hexadecimal MD5 hash
+of all prior lines of the manifest up to and including the newline
+character that immediately precedes the "Z", excluding any PGP
+clear-signing prefix. The <b>Z</b> card is
+a sanity check to prove that the manifest is well-formed and
+consistent.
+
+A sample manifest from Fossil itself can be seen
+[/artifact/28987096ac | here].
+
+<h3 id="cluster">2.2 Clusters</h3>
+
+A cluster is an artifact that declares the existence of other artifacts.
+Clusters are used during repository synchronization to help
+reduce network traffic. As such, clusters are an optimization and
+may be removed from a repository without loss or damage to the
+underlying project code.
+
+Allowed cards in the cluster are as follows:
+
+<div class="indent">
+<b>M</b> <i>artifact-id</i><br />
+<b>Z</b> <i>checksum</i>
+</div>
+
+A cluster contains one or more <b>M</b> cards followed by a single <b>Z</b> card.
+Each <b>M</b> card has a single argument which is the artifact ID of
+another artifact in the repository. The <b>Z</b> card works exactly like
+the <b>Z</b> card of a manifest. The argument to the <b>Z</b> card is the
+lower-case hexadecimal representation of the MD5 checksum of all
+prior cards in the cluster. The <b>Z</b> card is required.
+
+An example cluster from Fossil can be seen
+[/artifact/d03dbdd73a2a8 | here].
+
+<h3 id="ctrl">2.3 Control (a.k.a. Tag) Artifacts</h3>
+
+Control artifacts are used to assign properties to other artifacts
+within the repository. Allowed cards in a control artifact are as
+follows:
+
+<div class="indent">
+<b>D</b> <i>time-and-date-stamp</i><br />
+<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name</i> <i>artifact-id</i> ?<i>value</i>?<br />
+<b>U</b> <i>user-name</i><br />
+<b>Z</b> <i>checksum</i><br />
+</div>
+
+Control articles are also referred to as Tag artifacts, but tags can
+also be applied via other artifact types, as described in
+[#summary|the Card Summary table].
+
+A control artifact must have one <b>D</b> card, one <b>U</b> card, one <b>Z</b> card and
+one or more <b>T</b> cards. No other cards or other text is
+allowed in a control artifact. Control artifacts might be PGP
+clearsigned.
+
+The <b>D</b> card and the <b>Z</b> card of a control artifact are the same
+as in a manifest.
+
+The <b>T</b> card represents a [./branching.wiki#tags | tag or property]
+that is applied to
+some other artifact. The <b>T</b> card has two or three values. The
+second argument is the lowercase artifact ID of the artifact
+to which the tag is to be applied. The
+first value is the tag name. The first character of the tag
+is either "+", "-", or "*". The "+" means the tag should be added
+to the artifact. The "-" means the tag should be removed.
+The "*" character means the tag should be added to the artifact
+and all direct descendants (but not descendants through a merge) down
+to but not including the first descendant that contains a
+more recent "-", "*", or "+" tag with the same name.
+The optional third argument is the value of the tag. A tag
+without a value is a Boolean.
+
+When two or more tags with the same name are applied to the
+same artifact, the tag with the latest (most recent) date is
+used.
+
+Some tags have special meaning. The "comment" tag when applied
+to a check-in will override the check-in comment of that check-in
+for display purposes. The "user" tag overrides the name of the
+check-in user. The "date" tag overrides the check-in date.
+The "branch" tag sets the name of the branch that at check-in
+belongs to. Symbolic tags begin with the "sym-" prefix.
+
+The <b>U</b> card is the name of the user that created the control
+artifact. The <b>Z</b> card is the usual required artifact checksum.
+
+An example control artifact can be seen [/info/9d302ccda8 | here].
+
+
+<h3 id="wikichng">2.4 Wiki Pages</h3>
+
+A wiki artifact defines a single version of a
+single wiki page.
+Wiki artifacts accept
+the following card types:
+
+<div class="indent">
+<b>C</b> <i>change-comment</i><br>
+<b>D</b> <i>time-and-date-stamp</i><br />
+<b>L</b> <i>wiki-title</i><br />
+<b>N</b> <i>mimetype</i><br />
+<b>P</b> <i>parent-artifact-id</i>+<br />
+<b>U</b> <i>user-name</i><br />
+<b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
+<b>Z</b> <i>checksum</i>
+</div>
+
+The <b>D</b> card is the date and time when the wiki page was edited.
+The <b>P</b> card specifies the parent wiki pages, if any. The <b>L</b> card
+gives the name of the wiki page. The optional <b>N</b> card specifies
+the mimetype of the wiki text. If the <b>N</b> card is omitted, the
+mimetype is assumed to be text/x-fossil-wiki.
+The <b>U</b> card specifies the login
+of the user who made this edit to the wiki page. The <b>Z</b> card is
+the usual checksum over the entire artifact and is required.
+
+The <b>W</b> card is used to specify the text of the wiki page. The
+argument to the <b>W</b> card is an integer which is the number of bytes
+of text in the wiki page. That text follows the newline character
+that terminates the <b>W</b> card. The wiki text is always followed by one
+extra newline.
+
+The <b>C</b> card on a wiki page is optional. The argument is a comment
+that explains why the changes were made. The ability to have a <b>C</b>
+card on a wiki page artifact was added on 2019-12-02 at the suggestion
+of user George Krivov and is not currently used or generated by the
+implementation. Older versions of Fossil will reject a wiki-page
+artifact that includes a <b>C</b> card.
+
+An example wiki artifact can be seen
+[/artifact?name=7b2f5fd0e0&txt=1 | here].
+
+Historical note: though <b>U</b> cards are technically required for
+wiki pages by this specification, Fossil has historically elided them
+if the submitter is "nobody". Very few repositories enable "nobody" to
+write to wiki pages, so relatively few wiki artifacts without U cards
+exist, but they do exist. Implementations are recommended to accept a
+missing U card as an alias for a U card with the value
+<tt>nobody</tt>.
+
+<h3 id="tktchng">2.5 Ticket Changes</h3>
+
+A ticket-change artifact represents a change to a trouble ticket.
+The following cards are allowed on a ticket change artifact:
+
+<div class="indent">
+<b>D</b> <i>time-and-date-stamp</i><br />
+<b>J</b> ?<b>+</b>?<i>name</i> ?<i>value</i>?<br />
+<b>K</b> <i>ticket-id</i><br />
+<b>U</b> <i>user-name</i><br />
+<b>Z</b> <i>checksum</i>
+</div>
+
+The <b>D</b> card is the usual date and time stamp and represents the point
+in time when the change was entered. The <b>U</b> card is the login of the
+programmer who entered this change. The <b>Z</b> card is the required checksum over
+the entire artifact.
+
+Every ticket has a distinct ticket-id:
+40-character lower-case hexadecimal number.
+The ticket-id is given in the <b>K</b> card. A ticket exists if it contains one or
+more changes. The first "change" to a ticket is what brings the
+ticket into existence.
+
+<b>J</b> cards specify changes to the "value" of "fields" in the ticket.
+If the <i>value</i> parameter of the <b>J</b> card is omitted, then the
+field is set to an empty string.
+Each fossil server has a ticket configuration which specifies the fields it
+understands. The ticket configuration is part of the local state for
+the repository and thus can vary from one repository to another.
+Hence a <b>J</b> card might specify a <i>field</i> that does not exist in the
+local ticket configuration. If a <b>J</b> card specifies a <i>field</i> that
+is not in the local configuration, then that <b>J</b> card
+is simply ignored.
+
+The first argument of the <b>J</b> card is the field name. The second
+value is the field value. If the field name begins with "+" then
+the value is appended to the prior value. Otherwise, the value
+on the <b>J</b> card replaces any previous value of the field.
+The field name and value are both encoded using the character
+escapes defined for the <b>C</b> card of a manifest.
+
+An example ticket-change artifact can be seen
+[/artifact/91f1ec6af053 | here].
+
+<h3 id="attachment">2.6 Attachments</h3>
+
+An attachment artifact associates some other artifact that is the
+attachment (the source artifact) with a ticket, wiki page, technical
+note, or forum post to which the attachment is connected (the target
+artifact). The following cards are allowed on an attachment artifact:
+
+<div class="indent">
+<b>A</b> <i>filename target</i> ?<i>source</i>?<br />
+<b>C</b> <i>comment</i><br />
+<b>D</b> <i>time-and-date-stamp</i><br />
+<b>N</b> <i>mimetype</i><br />
+<b>U</b> <i>user-name</i><br />
+<b>Z</b> <i>checksum</i>
+</div>
+
+The <b>A</b> card specifies a filename for the attachment in its first
+argument. The second argument to the <b>A</b> card is the name of the
+wiki page, ticket, technical note, or full hash of a forum post to
+which the attachment is connected. The third argument is either
+missing or else it is the lower-case artifact ID of the attachment
+itself. A missing third argument means that the attachment should be
+deleted. If <i>target</i> is a forum post, the hash provided should
+generally be that of the first version of the post for reasons
+[#forumpost-tag|explained elsewhere].
+
+The <b>C</b> card is an optional comment describing what the attachment is about.
+The <b>C</b> card is optional, but there can only be one.
+
+A single <b>D</b> card is required to give the date and time when the attachment
+was applied.
+
+There may be zero or one <b>N</b> cards. The <b>N</b> card specifies the mimetype of the
+comment text provided in the <b>C</b> card. If the <b>N</b> card is omitted, the <b>C</b> card
+mimetype is taken to be text/plain.
+
+A single <b>U</b> card gives the name of the user who added the attachment.
+If an attachment is added anonymously, then the <b>U</b> card may be omitted.
+
+The <b>Z</b> card is the usual checksum over the rest of the attachment artifact.
+The <b>Z</b> card is required.
+
+
+<h3 id="event">2.7 Technical Notes</h3>
+
+A technical note or "technote" artifact (formerly known as an "event" artifact)
+associates a timeline comment and a page of text
+(similar to a wiki page) with a point in time. Technotes can be used
+to record project milestones, release notes, blog entries, process
+checkpoints, or news articles.
+The following cards are allowed on a technote artifact:
+
+<div class="indent">
+<b>C</b> <i>comment</i><br>
+<b>D</b> <i>time-and-date-stamp</i><br />
+<b>E</b> <i>technote-time</i> <i>technote-id</i><br />
+<b>N</b> <i>mimetype</i><br />
+<b>P</b> <i>parent-artifact-id</i>+<br />
+<b>T</b> <b>+</b><i>tag-name</i> <b>*</b> ?<i>value</i>?<br />
+<b>U</b> <i>user-name</i><br />
+<b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
+<b>Z</b> <i>checksum</i>
+</div>
+
+The <b>C</b> card contains text that is displayed on the timeline for the
+technote. The <b>C</b> card is optional, but there can only be one.
+
+A single <b>D</b> card is required to give the date and time when the
+technote artifact was created. This is different from the time at which
+the technote appears on the timeline.
+
+A single <b>E</b> card gives the time of the technote (the point on the timeline
+where the technote is displayed) and a unique identifier for the technote.
+When there are multiple artifacts with the same technote-id, the one with
+the most recent <b>D</b> card is the only one used. The technote-id must be a
+40-character lower-case hexadecimal string.
+
+The optional <b>N</b> card specifies the mimetype of the text of the technote
+that is contained in the <b>W</b> card. If the <b>N</b> card is omitted, then the
+<b>W</b> card text mimetype is assumed to be text/x-fossil-wiki, which is the
+Fossil wiki format.
+
+The optional <b>P</b> card specifies a prior technote with the same technote-id
+from which the current technote is an edit. The <b>P</b> card is a hint to the
+system that it might be space efficient to store one technote as a delta of
+the other.
+
+A technote might contain one or more <b>T</b> cards used to set
+[./branching.wiki#tags | tags or properties]
+on the technote. The format of the <b>T</b> card is the same as
+described in [#ctrl | Control Artifacts] section above, except that the
+second argument is the single character "<b>*</b>" instead of an
+artifact ID and the name is always prefaced by "<b>+</b>".
+The <b>*</b> in place of the artifact ID indicates that
+the tag or property applies to the current artifact. It is not
+possible to encode the current artifact ID as part of an artifact,
+since the act of inserting the artifact ID would change the artifact ID,
+hence a <b>*</b> is used to represent "self". The "<b>+</b>" on the
+name means that tags can only be "add" and they can only be non-propagating
+tags. In a technote, <b>T</b> cards are normally used to set the background
+display color for timelines.
+
+The optional <b>U</b> card gives the name of the user who entered the technote.
+
+A single <b>W</b> card provides wiki text for the document associated with the
+technote. The format of the <b>W</b> card is exactly the same as for a
+[#wikichng | wiki artifact].
+
+The <b>Z</b> card is the required checksum over the rest of the artifact.
+
+<h3 id="forum">2.8 Forum Posts</h3>
+
+Forum posts are intended as a mechanism for users and developers to
+discuss a project. Forum posts are like messages on a mailing list.
+
+The following cards are allowed on an forum post artifact:
+
+<div class="indent">
+<b>D</b> <i>time-and-date-stamp</i><br />
+<b>G</b> <i>thread-root</i><br />
+<b>H</b> <i>thread-title</i><br />
+<b>I</b> <i>in-reply-to</i><br />
+<b>N</b> <i>mimetype</i><br />
+<b>P</b> <i>parent-artifact-id</i><br />
+<b>U</b> <i>user-name</i><br />
+<b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
+<b>Z</b> <i>checksum</i>
+</div>
+
+Every forum post must have either one <b>I</b> card and one <b>G</b> card
+or one <b>H</b> card.
+Forum posts are organized into topic threads. The initial
+post for a thread (the root post) has an <b>H</b> card giving the title or
+subject for that thread. The argument to the <b>H</b> card is a string
+in the same format as a comment string in a <b>C</b> card.
+All follow-up posts have an <b>I</b> card that
+indicates which prior post in the same thread the current forum
+post is replying to, and a <b>G</b> card specifying the root post for
+the entire thread. The argument to <b>G</b> and <b>I</b> cards is the
+artifact hash for the prior forum post to which the card refers.
+
+In theory, it is sufficient for follow-up posts to have only an
+<b>I</b> card, since the <b>G</b> card value could be computed by following a
+chain of <b>I</b> cards. However, the <b>G</b> card is required in order to
+associate the artifact with a forum thread in the case where an
+intermediate artifact in the <b>I</b> card chain is shunned or otherwise
+becomes unreadable.
+
+A single <b>D</b> card is required to give the date and time when the
+forum post was created.
+
+The optional <b>N</b> card specifies the mimetype of the text of the technote
+that is contained in the <b>W</b> card. If the <b>N</b> card is omitted, then the
+<b>W</b> card text mimetype is assumed to be text/x-fossil-wiki, which is the
+Fossil wiki format.
+
+The optional <b>P</b> card specifies a prior forum post for which this
+forum post is an edit. For display purposes, only the child post
+is shown, though the historical post is retained as a record.
+If <b>P</b> cards are used and there exist multiple versions of the same
+forum post, then <b>I</b> cards for other artifacts refer to whichever
+version of the post was current at the time the reply was made,
+but <b>G</b> cards refer to the initial, unedited root post for the thread.
+Thus, following the chain of <b>I</b> cards back to the root of the thread
+may land on a different post than the one given in the <b>G</b> card.
+However, following the chain of <b>I</b> cards back to the thread root,
+then following <b>P</b> cards back to the initial version of the thread
+root must give the same artifact as is provided by the <b>G</b> card,
+otherwise the artifact containing the <b>G</b> card is considered invalid
+and should be ignored.
+
+In general, <b>P</b> cards may contain multiple arguments, indicating a
+merge. But since forum posts cannot be merged, the
+<b>P</b> card of a forum post may only contain a single argument.
+
+The <b>U</b> card gives name of the user who entered the forum post.
+
+A single <b>W</b> card provides wiki text for the forum post.
+The format of the <b>W</b> card is exactly the same as for a
+[#wikichng | wiki artifact].
+
+The <b>Z</b> card is the required checksum over the rest of the artifact.
+
+<a name="forumpost-tag"></a>
+<h4>2.8.1 Tags and Attachments on Forum Posts</h4>
+
+When adding [#ctrl|tags] or [#attachment|attachments] to [#forum|forum
+posts] it is generally up to the application to tag, or attach to,
+only the first version of any given post. For example, if post X has
+two edits then a tag applied, or attachment added, by the user to post
+X+2 should generally be applied to version X instead. Though this
+complicates the app logic for applying tags, it simplifies the app's
+location of tags for purposes of applying tag-/attachment-dependent
+logic. As of this writing (May 2026), no current Fossil use cases
+would be improved by tagging specific subsequent versions of posts,
+e.g. the hypothetical X+1.
+
+Forum posts, because they have a P-card, support propagating tags.
+
+
+<h2 id="summary">3.0 Card Summary</h2>
+
+The following table summarizes the various kinds of cards that appear
+on Fossil artifacts. A blank entry means that combination of card and
+artifact is not legal. A number or range of numbers indicates the number
+of times a card may (or must) appear in the corresponding artifact type.
+e.g. a value of 1 indicates a required unique card and 1+ indicates that one
+or more such cards are required.
+
+<table>
+<tr>
+<th>⇩ Card Format / Used By ⇨</th>
+<th>Manifest</th>
+<th>Cluster</th>
+<th>Control</th>
+<th>Wiki</th>
+<th>Ticket</th>
+<th>Attachment</th>
+<th>Technote</th>
+<th>Forum</th>
+</tr>
+<tr>
+<td><b>A</b> <i>filename</i> <i>target</i> ?<i>source</i>?</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>B</b> <i>baseline</i></td>
+<td align=center><b>0-1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>C</b> <i>comment-text</i></td>
+<td align=center><b>1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b></td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b></td>
+<td align=center><b>0-1</b></td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>D</b> <i>date-time-stamp</i></td>
+<td align=center><b>1</b></td>
+<td>&nbsp;</td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+</tr>
+<tr>
+<td><b>E</b> <i>technote-time technote-id</i></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>1</b></td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>F</b> <i>filename</i> ?<i>uuid</i>? ?<i>permissions</i>? ?<i>oldname</i>?</td>
+<td align=center><b>0+</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>G</b> <i>thread-root</i></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b></td>
+</tr>
+<tr>
+<td><b>H</b> <i>thread-title</i></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b><sup><nowiki>[4]</nowiki></sup></td>
+</tr>
+<tr>
+<td><b>I</b> <i>in-reply-to</i></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b><sup><nowiki>[4]</nowiki></sup></td>
+</tr>
+<tr>
+<td><b>J</b> <i>name</i> ?<i>value</i>?</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>1+</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>K</b> <i>ticket-uuid</i></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>L</b> <i>wiki-title</i></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>M</b> <i>uuid</i></td>
+<td>&nbsp;</td>
+<td align=center><b>1+</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>N</b> <i>mimetype</i></td>
+<td align=center><b>0-1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b></td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b></td>
+<td align=center><b>0-1</b></td>
+<td align=center><b>0-1</b></td>
+</tr>
+<tr>
+<td><b>P</b> <i>uuid ...</i></td>
+<td align=center><b>0-1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>0-1</b></td>
+<td align=center><b>0-1</b><sup><nowiki>[5]</nowiki></sup></td>
+</tr>
+<tr>
+<td><b>Q</b> (<b>+</b>|<b>-</b>)<i>uuid</i> ?<i>uuid</i>?</td>
+<td align=center><b>0+</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>R</b> <i>md5sum</i></td>
+<td align=center><b>0-1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<tr>
+<td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname</i> <i>uuid</i> ?<i>value</i>?<sup><nowiki>[1]</nowiki></sup></td>
+<td align=center><b>0+</b></td>
+<td>&nbsp;</td>
+<td align=center><b>1+</b><sup><nowiki>[2]</nowiki></sup></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>0+</b><sup><nowiki>[3]</nowiki></sup></td>
+<td>&nbsp;</td>
+</tr>
+<tr>
+<td><b>U</b> <i>username</i></td>
+<td align=center><b>1</b></td>
+<td>&nbsp;</td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>0-1</b></td>
+<td align=center><b>0-1</b></td>
+<td align=center><b>1</b></td>
+</tr>
+<tr>
+<td><b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>1</b></td>
+<td>&nbsp;</td>
+<td>&nbsp;</td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+</tr>
+<tr>
+<td><b>Z</b> <i>md5sum</i></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+<td align=center><b>1</b></td>
+</tr>
+</table>
+
+Footnotes:
+
+1) T-card names may not be made up of only hexadecimal characters, as
+ they would be indistinguishable from a hash prefix.
+
+2) Tags in [#ctrl | Control Artifacts] may not be
+ self-referential. i.e. their target hash may not be <tt>*</tt>.
+
+3) Tags in [#event | Technotes] must be self-referential. i.e. their
+ target hash must be <tt>*</tt>. Similarly, technote tags may only
+ be non-propagating "add" tags. i.e. their name prefix must be
+ <tt>+</tt>.
+
+4) [#forum | Forum Posts] must have either one H-card or one
+ I-card, not both.
+
+5) [#forum | Forum Post] P-cards may have only a single parent
+ hash. i.e. they may not have merge parents.
+
+<h2 id="addenda">4.0 Addenda</h2>
+
+This section contains additional information which may be useful when
+implementing algorithms described above.
+
+<h3 id="outofordercards">4.1 Relaxed Card Ordering Due To An Historical Bug</h3>
+
+All cards of a structural artifact should be in lexicographical order.
+The Fossil implementation verifies this and rejects any structural
+artifact which has out-of-order cards. Futhermore, when Fossil is
+generating new structural artifacts, it runs the generated artifact
+through the parser to confirm that all cards really are in the correct
+order before committing the transaction. In this way, Fossil prevents
+bugs in the code from accidentally inserting misformatted artifacts.
+The test parse of newly created artifacts is part of the
+[./selfcheck.wiki|self-check strategy] of Fossil. It takes a
+few more CPU cycles to double check each artifact before inserting it.
+The developers consider those CPU cycles well-spent.
+
+However, the card-order safety check was accidentally disabled due to
+[15d04de574383d61|a bug].
+And while that bug was lurking undetected in the code,
+[5e67a7f4041a36ad|another bug] caused the N cards of Technical Notes
+to occur after the P card rather than before.
+Thus for a span of several years, Technical Note artifacts were being
+inserted into Fossil repositories that had their N and P cards in the
+wrong order.
+
+Both bugs have now been fixed. However, to prevent historical
+Technical Note artifacts that were inserted by users in good faith
+from being rejected by newer Fossil builds, the card ordering
+requirement is relaxed slightly. The actual implementation is this:
+
+<p class=blockquote>
+"All cards must be in strict lexicographic order, except that the
+N and P cards of a Technical Note artifact are allowed to be
+interchanged."
+</p>
+
+Future versions of Fossil might strengthen this slightly to only allow
+the out of order N and P cards for Technical Notes entered before
+a certain date.
+
+<h3>4.2 R-Card Hash Calculation</h3>
+
+Given a manifest file named <tt>MF</tt>, the following Bash shell code
+demonstrates how to compute the value of the <b>R</b> card in that manifest.
+This example uses manifest [28987096ac]. Lines starting with <tt>#</tt> are
+shell input and other lines are output. This demonstration assumes that the
+file versions represented by the input manifest are checked out
+under the current directory.
+
+<nowiki><pre>
+# head MF
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+C Make\sthe\s"clearsign"\sPGP\ssigning\sdefault\sto\soff.
+D 2010-02-23T15:33:14
+F BUILD.txt 4f7988767e4e48b29f7eddd0e2cdea4555b9161c
+F COPYRIGHT-GPL2.txt 06877624ea5c77efe3b7e39b0f909eda6e25a4ec
+...
+
+# grep '^R ' MF
+R c0788982781981c96a0d81465fec7192
+
+# for i in $(awk '/^F /{print $2}' MF); do \
+ echo $i $(stat -c '%s' $i); \
+ cat $i; \
+done | md5sum
+c0788982781981c96a0d81465fec7192 -
+</pre></nowiki>
+
+Minor caveats: the above demonstration will work only when none of the
+filenames in the manifest are "fossilized" (encoded) because they contain
+spaces. In that case the shell-generated hash would differ because the
+<tt>stat</tt> calls will fail to find such files (which are output in encoded
+form here). That approach also won't work for delta manifests. Calculating
+the <b>R</b> card for delta manifests requires traversing both the delta and its baseline in
+lexical order of the files, preferring the delta's copy if both contain
+a given file.