Index: /trunk/cli/conversion.ml
===================================================================
--- /trunk/cli/conversion.ml	(revision 19)
+++ /trunk/cli/conversion.ml	(revision 20)
@@ -1,5 +1,6 @@
 open Logarion
 type t = {
-	id: string; dir: string;
+	id: string;
+	dir: string;
 	kv: string Store.KV.t;
 	topic_roots: string list;
@@ -13,2 +14,10 @@
 	indices: (t -> unit) option;
 }
+
+let empty () = {
+	id = ""; dir = "";
+	kv = Store.KV.empty;
+	topic_roots = [];
+	topics = Topic_set.Map.empty;
+	texts = []
+}
Index: /trunk/cli/convert.ml
===================================================================
--- /trunk/cli/convert.ml	(revision 19)
+++ /trunk/cli/convert.ml	(revision 20)
@@ -1,6 +1,6 @@
 open Logarion
 
-let is_older source dest = try
-	Unix.((stat dest).st_mtime < (stat source).st_mtime) with _-> true
+(*TODO: move to converters (style, feed checks)*)
+let is_older s d = try Unix.((stat d).st_mtime < (stat s).st_mtime) with _-> true
 
 let convert cs r (text, files) = match Text.str "Content-Type" text with
@@ -27,12 +27,11 @@
 	t
 
-let directory converters noindex dir id kv =
-	let empty = Topic_set.Map.empty in
-	let repo = Conversion.{ id; dir; kv; topic_roots = []; topics = empty; texts = [] } in
+let directory converters noindex repo =
 	let fn (ts,ls,acc) ((elt,_) as r) =
 		(Topic_set.to_map ts (Text.set "topics" elt)), elt::ls,
 		if convert converters repo r then acc+1 else acc in
-	let topics, texts, count = File_store.(fold ~dir ~order:newest fn (empty,[],0)) in
-	let topic_roots = try List.rev @@ String_set.list_of_csv (Store.KV.find "Topics" kv)
+	let topics, texts, count =
+		File_store.(fold ~dir:repo.Conversion.dir ~order:newest fn (Topic_set.Map.empty,[],0)) in
+	let topic_roots = try List.rev @@ String_set.list_of_csv (Store.KV.find "Topics" repo.kv)
 		with Not_found -> Topic_set.roots topics in
 	let repo = Conversion.{ repo with topic_roots; topics; texts } in
@@ -40,26 +39,32 @@
 	Printf.printf "Converted: %d Indexed: %d\n" count (List.length texts)
 
-let at_path types noindex path =
-	match path with "" -> prerr_endline "unspecified text file or directory"
-	| dir when Sys.file_exists dir && Sys.is_directory dir ->
-		let fname = Filename.concat dir "index.pck" in
-		(match Header_pack.of_string @@ File_store.to_string fname with
-		| Error s -> prerr_endline s
+let load_kv dir =
+	let conf = Filename.concat dir ".convert.conf" in (* TODO: better name? *)
+	let kv = if Sys.file_exists conf then File_store.of_kv_file conf else Store.KV.empty in
+	let idx = Filename.concat dir "index.pck" in
+	if not (Sys.file_exists idx) then kv else
+		match Header_pack.of_string @@ File_store.to_string (idx) with
+		| Error s -> prerr_endline s; kv
 		| Ok { info; peers; _ } ->
-			let kv = let f = Filename.concat dir ".convert.conf" in (* TODO: better place to store convert conf? *)
-				if Sys.file_exists f then File_store.of_kv_file f else Store.KV.empty in
+			let kv = if Store.KV.mem "Id" kv then kv else Store.KV.add "Id" info.Header_pack.id kv in
 			let kv = if Store.KV.mem "Title" kv then kv else Store.KV.add "Title" info.Header_pack.title kv in
 			let kv = Store.KV.add "Locations" (String.concat ";\n" info.Header_pack.locations) kv in
 			let kv = Store.KV.add "Peers" (String.concat ";\n" Header_pack.(to_str_list peers)) kv in
-			let cs = converters types kv in
-			directory cs noindex dir info.Header_pack.id kv)
+			kv
+
+let at_path types noindex path = match path with
+	| "" -> prerr_endline "unspecified text file or directory"
 	| path when Sys.file_exists path ->
-		let repo = Conversion.{
-			id = ""; dir = ""; kv = Store.KV.empty; topic_roots = [];
-			topics = Topic_set.Map.empty; texts = [] } in
-		let cs = converters types repo.kv in
-		(match File_store.to_text path with
-		| Ok text -> ignore @@ convert cs repo (text, [path])
-		| Error s -> prerr_endline s)
+		if Sys.is_directory path then (
+			let kv = load_kv path in
+			let repo = { (Conversion.empty ()) with dir = path; kv } in
+			directory (converters types kv) noindex repo
+		) else (
+			match File_store.to_text path with
+			| Error s -> prerr_endline s
+			| Ok text ->
+				let repo = { (Conversion.empty ()) with dir = ""; kv = load_kv "" } in
+				ignore @@ convert (converters types repo.kv) repo (text, [path])
+		)
 	| path -> Printf.eprintf "Path doesn't exist: %s" path
 
@@ -67,5 +72,5 @@
 let term =
 	let path = Arg.(value & pos 0 string "" & info [] ~docv:"path"
-		~doc:"Text file or directory to convert. Ff directory is provided, it must contain an index.pck (see: txt index)") in
+		~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
Index: /trunk/cli/html.ml
===================================================================
--- /trunk/cli/html.ml	(revision 19)
+++ /trunk/cli/html.ml	(revision 20)
@@ -1,8 +1,8 @@
 type templates_t = { header: string option; footer: string option }
-type t = { templates : templates_t }
+type t = { templates : templates_t; style : string }
 
 let ext = ".htm"
 let empty_templates = { header = None; footer = None }
-let default_opts = { templates = empty_templates }
+let default_opts = { templates = empty_templates; style = "" }
 
 let init kv =
@@ -13,25 +13,29 @@
 	let header = to_string "HTM-header" kv in
 	let footer = to_string "HTM-footer" kv in
-	{ templates = { header; footer} }
+	let style = match to_string "HTM-style" kv with
+		| Some s -> Printf.sprintf "<style>%s</style>" s | None -> "" in
+	{ templates = { header; footer}; style }
 
 let wrap conv htm text_title body =
-	let site_title = try Logarion.Store.KV.find "Title" conv.Conversion.kv
-		with Not_found -> "" in
+	let site_title = try Logarion.Store.KV.find "Title" conv.Conversion.kv with Not_found -> "" in
 	let replace x = let open Str in
-		global_replace (regexp "{{archive-title}}") site_title x
+		   global_replace (regexp "{{archive-title}}") site_title x
 		|> global_replace (regexp "{{text-title}}") text_title
 	in
+	let feed = try Logarion.Store.KV.find "HTM-feed" conv.Conversion.kv
+		with Not_found -> if Sys.file_exists (Filename.concat conv.Conversion.dir "feed.atom")
+			then "feed.atom" else "" in
 	let header = match htm.templates.header with 
-	| Some x -> replace x
-	| None -> "<header><a href='.'>" ^ site_title ^
-		"</a><nav><a href='feed.atom' id='feed'>feed</a></nav></header>"
+		| Some x -> replace x
+		| None -> Printf.(sprintf "<header><a href='.'>%s</a></header>%s" site_title
+				(if feed <> "" then sprintf "<nav><a href='%s' id='feed'>feed</a></nav>" feed else ""))
 	in
 	let footer = match htm.templates.footer with None -> "" | Some x -> replace x in
- 	Printf.sprintf "<!DOCTYPE HTML><html><head><title>%s%s</title>\n\
-	<link rel='stylesheet' href='main.css'>\
-	<link rel='alternate' href='feed.atom' type='application/atom+xml'>\
+	Printf.sprintf "<!DOCTYPE HTML><html><head><title>%s%s</title>\n%s\n%s\
 	<meta charset='utf-8'/><meta name='viewport' content='width=device-width, initial-scale=1.0'>\
 	</head><body>\n%s%s%s</body></html>"
 	text_title (if site_title <> "" then (" • " ^ site_title) else "")
+	htm.style
+	(if feed <> "" then Printf.sprintf "<link rel='alternate' href='%s' type='application/atom+xml'>" feed else "")
 	header body footer
 
@@ -151,5 +155,5 @@
 		^ "<nav><h1>Latest</h1><ul>" ^ to_dated_links ~limit:8 metas
 		^ {|</ul><a href="index.date.htm">More by date</a>|}
-		^ let peers = Logarion.Store.KV.find "Peers" conv.kv in
+		^ let peers = try Logarion.Store.KV.find "Peers" conv.kv with Not_found -> "" in
 			(if peers = "" then "" else
 				List.fold_left (fun a s -> Printf.sprintf {|%s<li><a href="%s">%s</a>|} a s s) "<h1>Peers</h1><ul>"
