Index: trunk/cli/authors.ml
===================================================================
--- trunk/cli/authors.ml	(revision 65)
+++ trunk/cli/authors.ml	(revision 66)
@@ -7,11 +7,16 @@
 	Person.Set.iter (fun x -> print_endline (Person.to_string x)) s
 
-open Ocmd
-let term =
-	let recurse = Arg.(value & flag & info ["R"]
-		~doc:"include texts in subdirectories too") in
-	let topics = Arg.(value & opt (some string) None & info ["topics"]
-		~docv:"TOPICS" ~doc:"display authors who have written on topics") in
-	Term.(const authors $ recurse $ topics),
-	Term.info "authors" ~doc:"list authors"
-		~man:[ `S "DESCRIPTION"; `P "List author names" ]
+open Cmdliner
+let recurse = Arg.(value & flag & info ["R"] ~doc: "Include texts in subdirectories too")
+let topics = Arg.(value & opt (some string) None & info ["topics"] ~docv:"topics" ~doc: "Display authors who have written on topics")
+
+let authors_t = Term.(const authors $ recurse $ topics)
+
+let cmd =
+  let doc = "List authors" in
+  let man = [
+      `S Manpage.s_description;
+      `P "List author names" ]
+  in
+  let info = Cmd.info "authors" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info authors_t
Index: trunk/cli/convert.ml
===================================================================
--- trunk/cli/convert.ml	(revision 65)
+++ trunk/cli/convert.ml	(revision 66)
@@ -77,14 +77,20 @@
 	| path -> Printf.eprintf "Path doesn't exist: %s" path
 
-open Ocmd
-let term =
-	let path = Arg.(value & pos 0 string "" & info [] ~docv:"path"
-		~doc:"Text file or directory to convert. If directory is provided, it must contain an index.pck (see: txt index)") in
-	let types = Arg.(value & opt string "all" & info ["t"; "type"] ~docv:"output type"
-		~doc:"Convert to file type") in
-	let noindex = Arg.(value & flag & info ["noindex"]
-		~doc:"Don't create indices in target format") in
-	Term.(const at_path $ types $ noindex $ path),
-	Term.info "convert" ~doc:"convert texts"
-		~man:[ `S "DESCRIPTION"; `P "Convert text or indexed texts within a directory to another format.
-		If path is a directory must contain an index.pck. Run `txt index` first." ]
+open Cmdliner
+
+let path = Arg.(value & pos 0 string "" & info [] ~docv:"path" ~doc:"Text file or directory to convert. If directory is provided, it must contain an index.pck (see: txt index)")
+let types = Arg.(value & opt string "all" & info ["t"; "type"] ~docv:"output type" ~doc:"Convert to file type")
+let noindex = Arg.(value & flag & info ["noindex"] ~doc:"Don't create indices in target format")
+
+let convert_t = Term.(const at_path $ types $ noindex $ path)
+
+let cmd =
+  let doc = "Convert texts" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Convert text or indexed texts within a directory to another format.";
+      `P "If path is a directory must contain an index.pck.";
+      `P "Run `txt index` first." ]
+  in
+  let info = Cmd.info "convert" ~version: "%%VERSION%%" ~doc ~man in
+  Cmd.v info convert_t
Index: trunk/cli/dune
===================================================================
--- trunk/cli/dune	(revision 65)
+++ trunk/cli/dune	(revision 66)
@@ -3,4 +3,4 @@
  (public_name txt)
  (modules txt authors convert conversion edit file index last listing
-  new topics html atom gemini peers pull read recent)
- (libraries text_parse.converter text_parse.parsers logarion msgpck curl str cmdliner))
+  new topics html atom gemini peers pull read recent unfile)
+ (libraries text_parse.converter text_parse.parsers logarion msgpck curl str cmdliner ocmd))
Index: trunk/cli/edit.ml
===================================================================
--- trunk/cli/edit.ml	(revision 65)
+++ trunk/cli/edit.ml	(revision 66)
@@ -1,16 +1,20 @@
-open Ocmd
-let term =
-	let id = Arg.(value & pos 0 string "" & info [] ~docv:"text ID") in
-	let recurse = Arg.(value & flag & info ["R"] ~doc:"recurse, include subdirs") in
-	let reverse = Arg.(value & flag & info ["r"] ~doc:"reverse order") in
-	let time   = Arg.(value & flag & info ["t"] ~doc:"sort by time, newest first") in
-	let number = Arg.(value & opt (some int) None & info ["n"]
-		~docv:"number" ~doc:"number of entries to list") in
-	let authed = Arg.(value & opt (some string) None & info ["authored"]
-		~docv:"comma-separated names" ~doc:"texts by authors") in
-	let topics = Arg.(value & opt (some string) None & info ["topics"]
-		~docv:"comma-separated topics" ~doc:"texts with topics") in
-	Term.(const (Logarion.Archive.apply_sys_util "EDITOR" "nano") $ recurse $ time $ reverse $ number $ authed $ topics $ id),
-	Term.info "edit" ~doc: "edit a text" ~man:[ `S "DESCRIPTION";
-		`P "Launches EDITOR (nano if environment variable is unset) with text path as parameter. 
-                If -R is used, the ID search space includes texts found in subdirectories too" ]
+open Cmdliner
+let id = Arg.(value & pos 0 string "" & info [] ~docv: "text ID")
+let recurse = Arg.(value & flag & info ["R"] ~doc: "Recurse into subdirectories")
+let reverse = Arg.(value & flag & info ["r"] ~doc: "Reverse order")
+let time = Arg.(value & flag & info ["t"] ~doc: "Sort by time, newest first")
+let number = Arg.(value & opt (some int) None & info ["n"] ~docv: "number" ~doc: "Number of entries to list")
+let authed = Arg.(value & opt (some string) None & info ["authored"] ~docv: "Comma-separated names" ~doc: "Texts by authors")
+let topics = Arg.(value & opt (some string) None & info ["topics"] ~docv: "Comma-separated topics" ~doc: "Texts by topics")
+
+let edit_t = Term.(const (Logarion.Archive.apply_sys_util "EDITOR" "nano") $ recurse $ time $ reverse $ number $ authed $ topics $ id)
+
+let cmd =
+  let doc = "Edit a text" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Launches EDITOR (nano if environment variable is unset) with text path as parameter.";
+      `P "If -R is used, the ID search space includes texts found in subdirectories, too." ]
+  in
+  let info = Cmd.info "edit" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info edit_t
Index: trunk/cli/file.ml
===================================================================
--- trunk/cli/file.ml	(revision 65)
+++ trunk/cli/file.ml	(revision 66)
@@ -9,26 +9,15 @@
 	List.iter (fun d -> List.iter (link d) files) dirs
 
-let unfile files =
-	let dirs, files = File_store.split_filetypes files in
-	let unlink dir file = try Unix.unlink (Filename.concat dir file)
-		with Unix.(Unix_error(ENOENT,_,_))-> () in
-	List.iter (fun d -> List.iter (unlink d) files) dirs
+open Cmdliner
+let files = Arg.(value & pos_all string [] & info [] ~docv: "Text filenames and subdirectories")
+let file_t = Term.(const file $ files)
 
-open Ocmd
-let term =
-	let files = Arg.(value & pos_all string [] & info []
-		~docv:"text filenames and subdirectories") in
-	Term.(const file $ files), Term.info "file"
-		~doc:"file texts in subdirectories"
-		~man:[ `S "DESCRIPTION"; `P "Files all texts in parameter in every
-		directory in parameter, using hardlinks.
-
-		Use it to create sub-repositories for sharing or converting" ]
-
-let unfile_term =
-	let files = Arg.(value & pos_all string [] & info []
-		~docv:"text filenames and subdirectories") in
-	Term.(const unfile $ files), Term.info "unfile"
-		~doc:"unfile texts from subdirectories"
-		~man:[ `S "DESCRIPTION"; `P "unfile texts in parameter from
-	directories in parameter, by removing hardlinks" ]
+let cmd =
+  let doc = "File texts in subdirectories" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Files all texts in parameter in every directory in parameter, using hardlinks";
+      `P "Use it to create sub-repositories for sharing or converting" ]
+  in
+  let info = Cmd.info "file" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info file_t
Index: trunk/cli/index.ml
===================================================================
--- trunk/cli/index.ml	(revision 65)
+++ trunk/cli/index.ml	(revision 66)
@@ -68,24 +68,24 @@
 	index { dir; index_path; pck = Header_pack.of_kv kv }
 
-open Ocmd
-let term =
-	let print= Arg.(value & flag & info ["print"] ~doc:"print info") in
-	let title= Arg.(value & opt ~vopt:(Some "") (some string) None & info ["t"; "title"]
-		~docv:"string" ~doc:"Title for index") in
-	let auth = Arg.(value & opt ~vopt:(Some "") (some string) None & info ["a"; "authors"]
-		~docv:"comma-separated names" ~doc:"Index authors") in
-	let locs = Arg.(value & opt ~vopt:(Some "") (some string) None & info ["l"; "locations"]
-		~docv:"comma-separated URLs" ~doc:"repository URLs") in
-	let peers= Arg.(value & opt ~vopt:(Some "") (some string) None & info ["p"; "peers"]
-		~docv:"comma-separated URLs" ~doc:"URLs to other known text repositories") in
-	let dir  = Arg.(value & pos 0 string "." & info []
-		~docv:"directory to index") in
-	let doc = "Generate an index.pck for texts in a directory" in
-	Term.(const load $ dir $ print $ title $ auth $ locs $ peers),
-		Term.info "index" ~doc
-			~man:[ `S "DESCRIPTION"; `Pre "An index contains:\n
-* an info section with: title for the index, the authors, locations (URLs) the texts can be access\n
-* listing of texts with: ID, date, title, authors, topics\n
-* list of other text repositories (peers)\n\n
-MessagePack format. <msgpack.org>"  ]
+open Cmdliner
+let print = Arg.(value & flag & info ["print"] ~doc: "Print info")
+let title = Arg.(value & opt ~vopt:(Some "") (some string) None & info ["t"; "title"] ~docv: "string" ~doc: "Title for index")
+let auth = Arg.(value & opt ~vopt:(Some "") (some string) None & info ["a"; "authors"] ~docv: "Comma-separated names" ~doc: "Index authors")
+let locs = Arg.(value & opt ~vopt:(Some "") (some string) None & info ["l"; "location"] ~docv: "Comma-separated URLs" ~doc: "Repository URLs")
+let peers = Arg.(value & opt ~vopt:(Some "") (some string) None & info ["p"; "peers"] ~docv: "Comma-separated URLs" ~doc: "URLs to other known text repositories")
+let dir = Arg.(value & pos 0 string "." & info [] ~docv: "Directory to index")
 
+let index_t = Term.(const load $ dir $ print $ title $ auth $ locs $ peers)
+
+let cmd =
+  let doc = "Generate an index.pck for texts in a directory" in
+  let man = [
+      `S Manpage.s_description;
+      `P "An index contains:\n";
+      `P "* n info section with: title for the index, the authors, locations (URLs) the texts can be accessed.";
+      `P "* listing of texts with: ID, date, title, authors, topics.";
+      `P "* list of other text repositories (peers)";
+      `S Manpage.s_see_also;
+      `P "MessagePack format. https://msgpack.org" ] in
+  let info = Cmd.info "index" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info index_t
Index: trunk/cli/last.ml
===================================================================
--- trunk/cli/last.ml	(revision 65)
+++ trunk/cli/last.ml	(revision 66)
@@ -21,8 +21,15 @@
 	| Some (_, f) -> List.iter print_endline f
 
-open Ocmd
-let term =
-	let mine = Arg.(value & flag & info ["mine"] ~doc:"last text authored by me") in
-	Term.(const last $ mine),
-	Term.info "last" ~doc:"most recent text"
-		~man:[ `S "DESCRIPTION"; `P "Print the filename of most recent text" ]
+open Cmdliner
+
+let mine = Arg.(value & flag & info ["mine"] ~doc: "Last text authored by me")
+let last_t = Term.(const last $ mine)
+
+let cmd =
+  let doc = "Most recent text" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Print the filename of most recent text" ]
+  in
+  let info = Cmd.info "last" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info last_t
Index: trunk/cli/listing.ml
===================================================================
--- trunk/cli/listing.ml	(revision 65)
+++ trunk/cli/listing.ml	(revision 66)
@@ -20,21 +20,25 @@
 		| None -> FS.iter ~r ~dir ~predicate ~order list_text
 
-open Ocmd
-let term =
-	let recurse = Arg.(value & flag & info ["R"] ~doc:"recurse, include subdirs") in
-	let reverse = Arg.(value & flag & info ["r"] ~doc:"reverse order") in
-	let time   = Arg.(value & flag & info ["t"] ~doc:"sort by time, newest first") in
-	let paths = Arg.(value & flag & info ["p"] ~doc:"show file paths") in
-	let number = Arg.(value & opt (some int) None & info ["n"]
-		~docv:"number" ~doc:"number of entries to list") in
-	let authed = Arg.(value & opt (some string) None & info ["authored"]
-		~docv:"comma-separated names" ~doc:"texts by authors") in
-	let topics = Arg.(value & opt (some string) None & info ["topics"]
-		~docv:"comma-separated topics" ~doc:"texts with topics") in
-	let dir  = Arg.(value & pos 0 string "" & info []
-		~docv:"directory to index") in
-	Term.(const listing $ recurse $ time $ reverse $ number $ paths $ authed $ topics $ dir),
-	Term.info "list" ~doc:"list texts" ~man:[ `S "DESCRIPTION";
-		`P "Diplays text id, date, author, title for a directory.
-		If directory argument is ommitted, TXTDIR is used, where empty value defaults to ~/.local/share/texts.
-		If -R is used, list header information for texts found in subdirectories too." ]
+open Cmdliner
+
+let recurse = Arg.(value & flag & info ["R"] ~doc: "Recurse into subdirectories")
+let reverse = Arg.(value & flag & info ["r"] ~doc: "Reverse order")
+let time = Arg.(value & flag & info ["t"] ~doc: "Sort by time, newest first")
+let paths = Arg.(value & flag & info ["p"] ~doc: "Show file paths")
+let number = Arg.(value & opt (some int) None & info ["n"] ~docv: "number" ~doc: "Number of entries to list")
+let authed = Arg.(value & opt (some string) None & info ["authored"] ~docv: "comma-separated names" ~doc: "Texts by authors")
+let topics = Arg.(value & opt (some string) None & info ["topics"] ~docv: "comma-separated topics" ~doc: "Texts by topics")
+let dir = Arg.(value & pos 0 string "" & info [] ~docv: "directory to index")
+
+let listing_t = Term.(const listing $ recurse $ time $ reverse $ number $ paths $ authed $ topics $ dir)
+
+let cmd =
+  let doc = "List texts" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Displays text id, date, author, title for a directory.";
+      `P "If directory argument is omitted, TXTDIR is used, where empty value defaults to ~/.local/share/texts.";
+      `P "If -R is used, list header information for texts found in subdirectories, too." ]
+  in
+  let info = Cmd.info "list" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info listing_t
Index: trunk/cli/new.ml
===================================================================
--- trunk/cli/new.ml	(revision 65)
+++ trunk/cli/new.ml	(revision 66)
@@ -1,4 +1,4 @@
 open Logarion
-open Ocmd
+open Cmdliner
 
 let new_txt title topics_opt interactive =
@@ -14,12 +14,16 @@
 		print_endline filepath
 
-let term =
-	let title = Arg.(value & pos 0 string "" & info []
-		~docv:"title" ~doc:"Title for new article") in
-	let topics= Arg.(value & opt (some string) None & info ["t"; "topics"]
-		~docv:"comma-separated topics" ~doc:"Topics for new article") in
-	let inter = Arg.(value & flag & info ["i"; "interactive"]
-		~doc:"Prompts through the steps of creation") in
-	Term.(const new_txt $ title $ topics $ inter), Term.info "new"
-		~doc:"create a new article" ~man:[ `S "DESCRIPTION";
-		`P "Create a new article, with title 'Draft' when none provided"]
+let title = Arg.(value & pos 0 string "" & info [] ~docv: "title" ~doc: "Title for new article")
+let topics = Arg.(value & opt (some string) None & info ["t"; "topics"] ~docv: "Comma-separated topics" ~doc: "Topics for new article")
+let inter = Arg.(value & flag & info ["i"; "interactive"] ~doc: "Prompt through the steps of creation")
+
+let new_t = Term.(const new_txt $ title $ topics $ inter)
+
+let cmd =
+  let doc = "Create a new article" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Create a new article, with title 'Draft' when none provided" ]
+  in
+  let info = Cmd.info "new" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info new_t
Index: trunk/cli/peers.ml
===================================================================
--- trunk/cli/peers.ml	(revision 65)
+++ trunk/cli/peers.ml	(revision 66)
@@ -29,9 +29,14 @@
 		Logarion.Peers.fold print_peer ()
 
-open Ocmd
-let term =
-	let remove = Arg.(value & opt (some string) None & info ["remove"]
-		~docv:"repository ID" ~doc:"remove repository texts & from future pulling") in
-	Term.(const peers $ remove),
-		Term.info "peers" ~doc:"list current peers" ~man:[ `S "DESCRIPTION";
-			`P "Lists current peers and associated information"]
+open Cmdliner
+let remove = Arg.(value & opt (some string) None & info ["remove"] ~docv:"Repository ID" ~doc:"Remove repository texts and from future pulling")
+let peers_t = Term.(const peers $ remove)
+
+let cmd =
+  let doc = "List current peers" in
+  let man = [
+      `S Manpage.s_description;
+      `P "List current peers and associated information" ]
+  in
+  let info = Cmd.info "peers" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info peers_t
Index: trunk/cli/pull.ml
===================================================================
--- trunk/cli/pull.ml	(revision 65)
+++ trunk/cli/pull.ml	(revision 66)
@@ -139,46 +139,17 @@
 	| "" -> pull_list auths topics | x -> ignore (pull_index x auths topics)
 
-open Ocmd
-let term =
-	let authors = Arg.(value & opt (some string) None & info ["a"; "authors"]
-		~docv:"comma-separated names" ~doc:"filter by authors") in
-	let topics = Arg.(value & opt (some string) None & info ["t"; "topics"]
-		~docv:"comma-separated topics" ~doc:"filter by topics") in
-	let url = Arg.(value & pos 0 string "" & info [] ~docv:"URL"
-		~doc:"Repository location") in
-	Term.(const pull $ url $ authors $ topics),
-		Term.info "pull" ~doc:"pull listed texts" ~man:[ `S "DESCRIPTION";
-			`P "Pull texts from known repositories. To add a new repository use:";
-			`P "txt pull [url]";
-			`P ("This creates a directory in " ^ Logarion.Peers.text_dir
-				^ " and downloads the text index.pck file in it")]
+open Cmdliner
+let authors = Arg.(value & opt (some string) None & info ["a"; "authors"] ~docv:"Comma-separated names" ~doc:"Filter by authors")
+let topics = Arg.(value & opt (some string) None & info ["t"; "topics"] ~docv:"Comma-separated topics" ~doc:"Filter by topics")
+let url = Arg.(value & pos 0 string "" & info [] ~docv:"URL" ~doc:"Repository location")
 
-(*module Msg = struct*)
-(*	type t = string * string*)
-(*	let compare (x0,y0) (x1,y1) =*)
-(*		match compare x1 x0 with 0 -> String.compare y0 y1 | c -> c*)
-(*end*)
-(*module MsgSet = Set.Make(Msg)*)
-(*let pull_msgs url _authors _topics =*)
-(*	match http_apply response url with*)
-(*	| Error msg ->*)
-(*		Printf.eprintf "Failed index request for %s %s" url msg*)
-(*	| Ok body ->*)
-(*		let rec fold_msgs s a fn =*)
-(*			let t, msg = Scanf.bscanf s "%s %s@\n" (fun t m -> t, m) in*)
-(*			if t <> "" then fold_msgs s (fn a t msg) fn else a*)
-(*		in*)
-(*		let s = Scanf.Scanning.from_string body in*)
-(*		let msgs = MsgSet.empty in*)
-(*		let date_string t = Ptime.to_date t |>*)
-(*			fun (y, m, d) -> Printf.sprintf "%04d-%02d-%02d" y m d in*)
-(*		let msgs = fold_msgs s msgs*)
-(*			(fun msgs t m -> match Ptime.of_rfc3339 t with*)
-(*			| Ok (v,_,_) -> let open MsgSet in*)
-(*				let msgs = if cardinal msgs > 1 then remove (max_elt msgs) msgs else msgs in*)
-(*				add (v,m) msgs*)
-(*			| _ -> msgs) in*)
-(*		let msg_string = MsgSet.fold*)
-(*			(fun (t,m) a -> a ^ Printf.sprintf "  %s 𐄁 %s\n" (date_string t) m)*)
-(*			msgs "" in*)
-(*		Printf.printf "┌───{ %s }───┐\n%s" url msg_string*)
+let pull_t = Term.(const pull $ url $ authors $ topics)
+
+let cmd =
+  let doc = "Pull listed texts" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Pull texts from known repositories." ]
+  in
+  let info = Cmd.info "pull" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info pull_t
Index: trunk/cli/read.ml
===================================================================
--- trunk/cli/read.ml	(revision 65)
+++ trunk/cli/read.ml	(revision 66)
@@ -1,18 +1,24 @@
 open Logarion
 
-open Ocmd
-let term =
-	let id = Arg.(value & pos 0 string "" & info [] ~docv:"text ID") in
-	let recurse = Arg.(value & flag & info ["R"] ~doc:"recurse, include subdirs") in
-	let reverse = Arg.(value & flag & info ["r"] ~doc:"reverse order") in
-	let time   = Arg.(value & flag & info ["t"] ~doc:"sort by time, newest first") in
-	let number = Arg.(value & opt (some int) None & info ["n"]
-		~docv:"number" ~doc:"number of entries to list") in
-	let authed = Arg.(value & opt (some string) None & info ["authored"]
-		~docv:"comma-separated names" ~doc:"texts by authors") in
-	let topics = Arg.(value & opt (some string) None & info ["topics"]
-		~docv:"comma-separated topics" ~doc:"texts with topics") in
-	Term.(const (Archive.apply_sys_util "PAGER" "less") $ recurse $ time $ reverse $ number $ authed $ topics $ id),
-	Term.info "read" ~doc: "read a text" ~man:[ `S "DESCRIPTION";
-		`P "List header information for current directory. If -R is used, list header
-		information for texts found in subdirectories too, along with their filepaths" ]
+open Cmdliner
+
+
+let id = Arg.(value & pos 0 string "" & info [] ~docv:"text ID")
+let recurse = Arg.(value & flag & info ["R"] ~doc:"recurse, include subdirs")
+let reverse = Arg.(value & flag & info ["r"] ~doc:"reverse order")
+let time   = Arg.(value & flag & info ["t"] ~doc:"sort by time, newest first")
+let number = Arg.(value & opt (some int) None & info ["n"] ~docv:"number" ~doc:"number of entries to list")
+let authed = Arg.(value & opt (some string) None & info ["authored"] ~docv:"comma-separated names" ~doc:"texts by authors")
+let topics = Arg.(value & opt (some string) None & info ["topics"] ~docv:"comma-separated topics" ~doc:"texts with topics")
+
+let read_t = Term.(const (Archive.apply_sys_util "PAGER" "less") $ recurse $ time $ reverse $ number $ authed $ topics $ id)
+
+let cmd =
+  let doc = "Read a text" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Deprecated. This subcommand will be removed in a future release of Logarion";
+      `P "This invokes the PAGER utility ('less' if unset) on an article of the archive" ]
+  in
+  let info = Cmd.info "read" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info read_t
Index: trunk/cli/recent.ml
===================================================================
--- trunk/cli/recent.ml	(revision 65)
+++ trunk/cli/recent.ml	(revision 66)
@@ -3,19 +3,21 @@
 module A = Archive
 
-open Ocmd
-let term =
-	let recurse = Arg.(value & flag & info ["R"] ~doc:"recurse, include subdirs") in
-	let reverse = Arg.(value & flag & info ["r"] ~doc:"reverse order") in
-	let paths = Arg.(value & flag & info ["p"] ~doc:"show file paths") in
-	let number = Arg.(value & opt (some int) (Some 10) & info ["n"]
-		~docv:"number" ~doc:"number of entries to list") in
-	let authed = Arg.(value & opt (some string) None & info ["authored"]
-		~docv:"comma-separated names" ~doc:"texts by authors") in
-	let topics = Arg.(value & opt (some string) None & info ["topics"]
-		~docv:"comma-separated topics" ~doc:"texts with topics") in
-	let dir  = Arg.(value & pos 0 string "" & info []
-		~docv:"directory to index") in
-	Term.(const Listing.listing $ recurse $ (const true) $ reverse $ number $ paths $ authed $ topics $ dir),
-	Term.info "recent" ~doc:"list recent texts" ~man:[ `S "DESCRIPTION";
-		`P "List header information of most recent texts. If -R is used, list header
-		information for texts found in subdirectories too, along with their filepaths" ]
+open Cmdliner
+let recurse = Arg.(value & flag & info ["R"] ~doc: "Recurse into subdirectories")
+let reverse = Arg.(value & flag & info ["r"] ~doc: "Reverse order")
+let paths = Arg.(value & flag & info ["p"] ~doc: "Show file paths")
+let number = Arg.(value & opt (some int) (Some 10) & info ["n"] ~docv: "number" ~doc: "Number of entries to list")
+let authed = Arg.(value & opt (some string) None & info ["authored"] ~docv: "Comma-separated names" ~doc: "Texts by authors")
+let topics = Arg.(value & opt (some string) None & info ["topics"] ~docv: "Comma-separated topics" ~doc: "Texts with topics")
+let dir = Arg.(value & pos 0 string "" & info [] ~docv: "Directory to index")
+
+let recent_t = Term.(const Listing.listing $ recurse $ (const true) $ reverse $ number $ paths $ authed $ topics $ dir)
+let cmd =
+  let doc = "List recent texts" in
+  let man = [
+      `S Manpage.s_description;
+      `P "List header information of most recent texts.";
+      `P "If -R is used, list header information for texts found in subdirectories, too, along with their filepaths" ]
+  in
+  let info = Cmd.info "recent" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info recent_t
Index: trunk/cli/topics.ml
===================================================================
--- trunk/cli/topics.ml	(revision 65)
+++ trunk/cli/topics.ml	(revision 66)
@@ -7,11 +7,15 @@
 	print_endline @@ String_set.to_string s
 
-open Ocmd
-let term =
-	let recurse = Arg.(value & flag & info ["R"]
-		~doc:"include texts in subdirectories") in
-	let authed = Arg.(value & opt (some string) None & info ["authored"]
-		~docv:"comma-separated authors" ~doc:"topics by authors") in
-	Term.(const topics $ recurse $ authed),
-		Term.info "topics" ~doc:"list topics" ~man:[ `S "DESCRIPTION";
-			`P "List of topics" ]
+open Cmdliner
+let recurse = Arg.(value & flag & info ["R"] ~doc: "Include texts in subdirectories")
+let authed = Arg.(value & opt (some string) None & info ["authored"] ~docv: "Comma-separated authors" ~doc: "Topics by authors")
+let topics_t = Term.(const topics $ recurse $ authed)
+
+let cmd =
+  let doc = "List topics" in
+  let man = [
+      `S Manpage.s_description;
+      `P "List of topics" ]
+  in
+  let info = Cmd.info "topics" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info topics_t
Index: trunk/cli/txt.ml
===================================================================
--- trunk/cli/txt.ml	(revision 65)
+++ trunk/cli/txt.ml	(revision 66)
@@ -1,21 +1,31 @@
-open Ocmd
-let default_cmd =
-	let doc = "Discover, collect & exchange texts" in
-	let man = [ `S "CONTACT"; `P "<mailto:logarion-dev@chaotic.ninja>" ] in
-	Term.(ret (const (`Help (`Pager, None)))), Term.info "txt" ~version:"%%VERSION%%" ~doc ~man
+open Cmdliner
 
-let () = match Term.eval_choice default_cmd [
-	Authors.term;
-	Convert.term;
-	Edit.term;
-	File.term; File.unfile_term;
-	Index.term;
-	Last.term;
-	Listing.term;
-	New.term;
-	Peers.term;
-	Pull.term;
-	Read.term;
-	Recent.term;
-	Topics.term;
-	] with `Error _ -> exit 1 | _ -> exit 0
+let subs = [
+    Authors.cmd; (* Done *)
+    Convert.cmd; (* Done *)
+    Edit.cmd; (* Done *)
+    File.cmd; (* Done *)
+    Index.cmd; (* Done *)
+    Last.cmd; (* Done *)
+    Listing.cmd; (* Done *)
+    New.cmd; (* Done *)
+    Peers.cmd; (* Done *)
+    Pull.cmd; (* Done *)
+    Read.cmd; (* Done *)
+    Recent.cmd; (* Done *)
+    Topics.cmd; (* Done *)
+    Unfile.cmd; (* Done *)
+  ]
+
+let default_cmd = Term.(ret (const (`Help (`Pager, None))))
+
+let txt =
+  let doc = "Discover, collect and exchange texts" in
+  let man = [
+      `S "CONTACT";
+      `P "<mailto:logarion-dev@chaotic.ninja>"; ]
+  in
+  Cmd.group (Cmd.info "txt" ~version:"%%VERSION%%" ~doc ~man) ~default:default_cmd subs
+
+let main () = exit (Cmd.eval txt)
+let () = main ()
Index: trunk/cli/unfile.ml
===================================================================
--- trunk/cli/unfile.ml	(revision 66)
+++ trunk/cli/unfile.ml	(revision 66)
@@ -0,0 +1,21 @@
+open Logarion
+
+let unfile files =
+  let dirs, files = File_store.split_filetypes files in
+  let unlink dir file = try Unix.unlink (Filename.concat dir file) with
+                          Unix.(Unix_error(ENOENT,_,_))-> () in
+  List.iter (fun d -> List.iter (unlink d) files) dirs
+
+open Cmdliner
+let files = Arg.(value & pos_all string [] & info [] ~docv: "Text filenames and subdirectories")
+
+let unfile_t = Term.(const unfile $ files)
+
+let cmd =
+  let doc = "Unfile texts from subdirectories" in
+  let man = [
+      `S Manpage.s_description;
+      `P "Unfile texts in parameter from directories in parameter, by removing hardlinks" ]
+  in
+  let info = Cmd.info "unfile" ~version:"%%VERSION%%" ~doc ~man in
+  Cmd.v info unfile_t
