Module: nexus (NexusCore.php, nexus_link.php, nexus_pair.php, nexus_tool.php, nexus_tidy.php) Version: 2.2.2 Date: 2026-10-26 Another collaboration between Andrew.human and Claude.ai
Audience: people, and machines or AIs that read the forum. Facts are stated flatly.
A nexus links posts into a project: a locked old post, the newer post that replaces it, posts that contribute to it, posts it depends on. The link goes between posts (messages), not topics.
Five kinds of link, written "A kind B". Direction matters: it is how nexus knows which post is the master and who sits under whom. Use related only for plain grouping with no hierarchy.
| Kind | Reads as | Example |
|---|---|---|
contributes |
A belongs under B (B is the master side) | an uninstall step, under the master post that describes the whole job. The default. |
related |
A and B belong together | no direction, no hierarchy |
supersedes |
A replaces B | the new topic's first post supersedes the locked old one |
depends |
A depends on B | A cannot be used without B |
uses |
project A uses project B | joins two separate projects without merging them (section 1a) |
A project is every post reachable from any other through links of any kind except uses. Add a link and the two projects it joins become one. Pairs can be added one at a time, as you go; groupings may become large and tangled, and that is fine: every post of a project shows the whole project.
uses)Sometimes a whole project depends on another whole project: the listatt project (its master is the post that describes listatt) is used by many later projects for their user interface. Linking a post of one to a post of the other with any other kind would merge them into one. A uses link does not:
php Sources/CollabCore/nexus_pair.php topic=8075 topic=7599 --kind=uses # the project of 8075 uses the project of 7599
Two posts already in one project cannot be joined by uses (the command says so).
A project has one master: its top post. But any post can also be flagged master of its own branch, meaning "this post heads the posts indented under it". You can flag as many posts as you like, whether or not anything is under them yet. Example, with Nexus at the top, then Listatt, then Collaborative:
Nexus (8075) MASTER of the project
└─ Listatt (7599) BRANCH MASTER (Collaborative is under it)
└─ Collaborative (7735) BRANCH MASTER (nothing under it yet)
php Sources/CollabCore/nexus_pair.php topic=7599 topic=8075 # Listatt belongs under Nexus
php Sources/CollabCore/nexus_pair.php topic=7735 topic=7599 # Collaborative belongs under Listatt
php Sources/CollabCore/nexus_tool.php branch topic=7599 # flag Listatt as a branch master
php Sources/CollabCore/nexus_tool.php branch topic=7735 # flag Collaborative too
php Sources/CollabCore/nexus_tool.php branch --list # every flagged post
php Sources/CollabCore/nexus_tool.php branch topic=7599 --clear # remove a flag
A branch flag changes only the labelling: NEXUS.md marks the post BRANCH MASTER in the hierarchy and says "master of its branch (N under it)" in the chronology; listatt shows a BRANCH MASTER badge. It does not move the post, and it does not touch the project's own master (master, section 6). It needs the table nexus_branches, which the package creates when installed or reinstalled.
php Sources/CollabCore/nexus_tool.php assign <post> <any post of the project> [--under=POST]
The post is linked under the project's master (or under --under, a post of that project). A post that is already in a project of its own is refused, because that would merge two projects; use unlink first, or join the projects with uses.
contributes to, or depends on, another sits under it. A post that was superseded sits under the post that replaced it, unless it already sits under something else. Where a post has several candidates, the earliest link wins. related links give no hierarchy.nexus_tool.php master <post>, or the admin page): that post goes to the top whatever the count says, and the former top posts hang directly under it. Everything else keeps its place. NEXUS.md and the listatt box say "chosen by hand". One hand-set master per project; setting another clears the first. A post that sat under another can be made master (its own parent link is set aside, not deleted).nexus_protected_boards, edited on the admin page): posts there cannot be linked, are never named, and are not counted. Links that touch such a post are dropped by the nightly job. Use this for material you must not let out, for example a post carrying a file you may not share.<forum>/Sources/nexus_link.php (administrators only, with a one-time form token).
msg=1234 or msg1234), or type topic=7735 for a topic's first post (the result says which post was used). Choose the kind. Linking writes or refreshes NEXUS.md on every post of the project.topic=N, then "Make master" or "Clear".A link between the same two posts, of the same kind, in either order, is a repeat. A link that repeats an existing one (either way round), links a post to itself, or touches a missing or protected post is refused with a reason.
One line, in the spirit of attachme: it links two posts, and writes NEXUS.md on every post of the resulting project.
php Sources/CollabCore/nexus_pair.php <A> <B> # A belongs under B (B = the master side)
php Sources/CollabCore/nexus_pair.php <A> <B> --kind=K # K = contributes (default) | depends | supersedes | related | uses
php Sources/CollabCore/nexus_pair.php <A> <B> --remove # remove the link(s) between A and B
php Sources/CollabCore/nexus_pair.php <A> --show # print the whole project post A belongs to
A and B are post (message) numbers, or pasted post addresses containing msg=1234 or msg1234, or a topic (topic=7735), which means that topic's first post. If both a post and a topic appear, the post wins. When a topic is used, the command prints a NOTE: line saying which post it was taken to be. --dry-run says what would happen and changes nothing. Run it from the forum root; it finds Settings.php by itself (--settings=PATH to override).
It prints the version, then one result line, and sets an exit code, so a script or an AI can act on it:
| Result line starts | Exit code | Meaning |
|---|---|---|
LINKED: |
0 | done; the line says which way it points (for example #1234 belongs under #1000) and lists every post now in the project |
REMOVED: / WOULD REMOVE: / WOULD LINK: |
0 | done, or what a dry run would do |
REFUSED: |
1 | not done; the line says why (post missing, same post twice, protected board, already linked, unknown kind) |
| (error on stderr) | 2 | could not start (no Settings.php, database down, table missing) |
Tip for AIs: run --show on a post first to see which project it already belongs to, then add the pair. The attachment gets the post's own member as owner, and when the command runs as root the file takes the owner and group of the attachment folder (as attachme does with chown), so the web server can manage it.
For everything that is not "link two posts": one command, many sub-commands. Run it from the forum root.
php Sources/CollabCore/nexus_tool.php <command> [posts] [options] # php nexus_tool.php --help lists them
Posts are numbers, pasted addresses (msg=1234) or topic=N (the topic's first post). Anything that deletes, or can touch more than one project, is a dry run unless you add --apply. Only master, branch and assign act at once. Changes wait for the nightly job: if nexus_tidy.php is running, the command stops with exit code 3.
| Command | What it does | Default |
|---|---|---|
master <post> |
Make that post the master of its project by hand | acts at once |
assign <post> <post of the project> [--under=POST] |
Put a post into a project (under its master, or under --under) |
acts at once |
branch <post> |
Flag a post as the master of its own branch (any number of posts; it needs no posts under it) | acts at once |
branch <post> --clear / branch --list |
Remove the flag / list flagged posts | acts at once / read-only |
master <post> --clear |
Remove the hand-set master; it is worked out from the links again | acts at once |
master --list |
Projects that have a hand-set master | read-only |
projects |
One line per project: master, size, first and last date, locked count, posts | read-only |
show <post> |
The whole project that post belongs to (the NEXUS.md text) | read-only |
check |
Health report: links to gone posts, links into protected boards, loops, two masters in one project, flags on loose posts, NEXUS.md with no file, orphan or duplicate NEXUS.md, missing or out-of-date NEXUS.md. Exit 1 if anything is wrong | read-only |
export [--public] [--format=json|csv] [--file=PATH] |
Everything as text: for a backup, or for another program such as ISE. JSON has every link, every project with step numbers, dates, parent, master and address. --public writes only titles that guests may see (all others read "Post N"). CSV can be read back by import |
read-only |
move <old> <new> |
Move every link, and a hand-set master flag, from one post to another (a topic was reposted or recreated). Links that would duplicate or loop onto themselves are dropped | dry run |
unlink <post> |
Remove every link of one post; it leaves its project (the project may split) | dry run |
dissolve <post> |
Remove every link in the post's project, and its hand-set master, and delete its NEXUS.md files | dry run |
rebuild <post> or rebuild --all |
Rewrite NEXUS.md even when it looks up to date (after a title format change, or to be sure) | dry run |
purge |
Delete every NEXUS.md attachment and file. Links and master flags are kept; nexus_tidy.php --apply or rebuild --all --apply makes the files again. Use before uninstalling if you want the attachments gone |
dry run |
import --file=PATH |
Load links from a text file. One per line: A,B (A belongs under B), A,B,kind, A,kind,B, or master,POST. # starts a comment. Each line is checked like a normal link. The dry run also catches a line repeated in the file, but not links that only become invalid because of other lines. NEXUS.md is written once at the end |
dry run |
nexus_tool.php master 1000. Put it back to automatic: master 1000 --clear. The post must already be linked into a project.nexus_pair.php 1234 1000 --remove (add --kind=K to remove just one kind).nexus_tool.php move <old post> <new post> --apply.unlink <post> --apply. The whole project is abandoned: dissolve <post> --apply.check, then nexus_tidy.php --apply repairs most things it finds.export --format=csv --file=/root/nexus_backup.csv; to restore after a dissolve, import --file=... --apply.export --public --file=nexus.json.import --file=lines.txt (read the dry run), then --apply.php Sources/CollabCore/nexus_tidy.php [options] (run from the forum root)
| Option | Meaning |
|---|---|
| (none) | Dry run. Prints what it would do, changes nothing. |
--apply |
Make the changes. |
--settings=PATH |
Settings.php to use. Default: searched upward from the script. |
--pause=MS |
Pause between posts (default 50) so the live forum is not starved. |
--stop |
Ordered stop: the running job finishes its current post, then exits. Nothing is killed. |
--help |
Option list. |
What it does, in order:
Only attachments named exactly NEXUS.md are ever created, rewritten or deleted. Running it twice in a row changes nothing the second time. Only one copy can run (lock file nexus_tidy.lock). The version prints once when it starts. When to schedule it is the operator's decision; an example line for cron, the system's timer, is:
cd /var/www/html && nice -n 19 php Sources/CollabCore/nexus_tidy.php --apply
Exit code 0 = finished, 1 = finished with errors (listed), 2 = could not start, 3 = already running.
Table {db_prefix}nexus_branches (v2.2.0): id_msg (a post flagged master of its own branch), id_member, added; any number of rows. Table {db_prefix}nexus_masters: id_msg (the post chosen by hand as master), id_member, added. Table {db_prefix}nexus_links: id_link, id_from, id_to, kind, id_member (who added it), added (time). One row per link; a link is unique per (from, to, kind). The NEXUS.md files are derived from this table and can always be remade by the nightly job.
A NEXUS.md is stored like any attachment: a row in {db_prefix}attachments (name NEXUS.md, type text/markdown, approved) and a file in the current attachment directory, written by a temporary file then renamed.
uses link joins two separate projects only for display: it never changes either project's master, hierarchy or step numbers, and it is never followed when a project is gathered. Titles in the Other projects section follow section 3 (only guest-visible titles in the file; per-viewer in the listatt box; protected boards never).| Version | Date | Change |
|---|---|---|
| 2.2.2 | 2026-10-26 | Fix: options after the post numbers were ignored. nexus_pair.php A B --remove tried to add a link, --dry-run after the posts did not make a dry run, and nexus_tool.php master P --clear / dissolve P --apply ignored the option (PHP's getopt() stops at the first plain argument). Options are now read anywhere on the line (--kind=uses or --kind uses), and an unknown option is an error. Affects nexus_pair.php and nexus_tool.php. |
| 2.2.1 | 2026-10-26 | Topic numbers everywhere: every display prints the topic number beside the post number ("#49331 (topic 7599)") - the NEXUS.md master line, hierarchy, chronology (new "Topic no." column; the old locked/open column is now "Topic status"), relations and other projects; the result lines of nexus_pair.php and nexus_tool.php; the projects list; the JSON export; and the admin page. |
| 2.2.0 | 2026-10-26 | Branch masters: nexus_tool.php branch <post> flags any number of posts as the master of their own branch (new table nexus_branches); NEXUS.md marks them BRANCH MASTER and counts the posts under each; import/export carry branch,POST lines; move carries the flag; the nightly job drops flags on gone or protected posts. Fixes: the projects list and check no longer join projects through uses links, and a post that only has a uses link is no longer reported as an orphan. Pairs with listatt 7.2.0. |
| 2.1.0 | 2026-10-26 | New link kind uses: joins two separate projects without merging them (each keeps its own master and outline); NEXUS.md gets an "Other projects" section; a single post can use a project. New command nexus_tool.php assign <post> <post of the project> [--under=POST]. nexus_link.php offers "uses". Pairs with listatt 7.1.0. |
| 2.0.0 | 2026-10-26 | Master by hand (new table nexus_masters; admin page form; nexus_tool.php master) and the maintenance toolkit nexus_tool.php: projects, show, check, export (JSON or CSV, --public), move, unlink, dissolve, rebuild, purge, import; deleting commands are dry runs unless --apply, and wait for the nightly job. Admin page lists projects. The nightly job drops stray master flags. Pairs with listatt 6.30. |
| 1.2.0 | 2026-10-26 | NEXUS.md names the master post, shows the hierarchy as an outline and the chronology (step numbers, first and latest date, span). The default pair is now "A belongs under B" (kind contributes); related stays for flat grouping. A link that would make a loop is refused. Pairs with listatt 6.29. |
| 1.1.2 | 2026-10-26 | FIX: post titles in NEXUS.md and on the admin page showed ", & and similar as text. SMF stores subjects already escaped; they are now decoded once. Angle brackets in a title become round brackets in NEXUS.md. Existing files are corrected by the nightly job (or by the next link on any post of the project). |
| 1.1.1 | 2026-10-26 | A post can be given as a topic (topic=N = that topic's first post) in nexus_pair.php and on the admin page; the result says which post was used. |
| 1.1.0 | 2026-10-24 | New link kind related (plain grouping, now the default); new command nexus_pair.php (link, --remove, --show, --dry-run); NEXUS.md attachments are owned by the post's member and, when made as root, by the folder's owner; the "current ones" lines appear only when a project has a supersedes link; admin page offers "related to". |
| 1.0.0 | 2026-10-24 | First release: link table, admin page, NEXUS.md showing the whole project, nightly tidy job, protected boards. Pairs with listatt 6.27. |